Before Umbraco 17 we didn’t use HMACSecretKey, so we didn’t have a problem using a WebP Middleware which automatically checked if WebP was supported and appended the “format=webp” if it was.
But this is not the case anymore
So we have begun using HMACSecretKey, but of course this will "alter” the URL after the HMAC has done it’s magic and then invalidating the Image URL.
How have you solved it the “issue” with serving WebP and using HMAC?
I have a webp middleware and HMAC on 17 and I haven’t seen the issue, Umbraco passes the secret to ImageSharp.Web so everything is calculated at the correct time, at least in my experience.
Webp support is widespread, so honestly, we only serve webp images these days.
However, if you want to support non-webp browsers, why don’t you simply create an image source set in the html with multiple formats? I agree that the html will get a little bigger, but you let the browser decide what it supports and what the correct size is that is needs. That saves on middleware processing time.
FWIW @AndersBrohus , I was working on this exact task just yesterday and was experiencing the same results.
We started out a new project on 17.1
We’re now on 17.2.2 and always convert all of our images to .webp
I followed the imaging settings documentation and all the images resulted in a 404.
I finally reverted the effort because i didn’t get to a timely victory, sigh!
Of note - it did not occur to me to try any other image formats so I didn’t think it was an .webp issue specifically.
Started seeing a similar issue myself now but its fine if the image is using GetCropUrl(…) so all the media based images are happy, however just a url with no crops or querystring I hit the issue as the HMAC querystring is missing
I know nothing. But given the approach above, I ran into the same issue. Once you apply formatting commands, I suspect a HMAC is required. i.e., a request with no image-crop commands has no HMAC, but once you apply a command, an HMAC (and a valid one) is required.
Thanks to this discussion, I realized that my AutoFormatImagesToWebp package didn’t support the HMACSecretKey setting. I’ve released a new version that should fix this issue, but I need feedback from someone who isn’t using my machine!
(There’s a little more happening in my package that may not make it suitable for everybody.)
I dont know if its sorta related or off topic, but we struggled a lot with hmac in our custom property editors. The documentation is useless in this regard, so after scouring umbracos own source code, I have this example:
import { html, css, state, customElement } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbImagingRepository } from '@umbraco-cms/backoffice/imaging';
import { ImageCropModeModel } from '@umbraco-cms/backoffice/external/backend-api';
@customElement('my-image-example')
export class MyImageExample extends UmbLitElement {
@state() private _imageUrl = '';
private _imagingRepository = new UmbImagingRepository(this);
override connectedCallback() {
super.connectedCallback();
this._loadImage('ca8b8552-8fcb-46c4-89db-bbaeac0e4351'); // replace with your media GUID
}
private async _loadImage(mediaKey: string) {
const { data } = await this._imagingRepository.requestResizedItems(
[mediaKey],
{
width: 256,
height: 128,
mode: ImageCropModeModel.CROP, // Crop | Max | Min | Stretch | Pad | BoxPad
format: 'webp', // optional — omit to keep original format
},
);
// data[0].url is an absolute HMAC-signed URL, e.g.:
// https://example.com/media/abc/image.jpg?rmode=crop&width=256&height=128&hmac=9946f2...
this._imageUrl = data[0]?.url ?? '';
}
override render() {
return html`<img src=${this._imageUrl} alt="" width="256" height="128" />`;
}
static styles = css`
img { display: block; }
`;
}
declare global {
interface HTMLElementTagNameMap {
'my-image-example': MyImageExample;
}
}
Something like that. Its of course not a proper property editor, just an example. But the key is @umbraco-cms/backoffice/imaging UmbImagingRepository , this gives you a url with hmac. In general I would from now on recommend using this to get your images in your backoffice extensions going forward as it has other features, like batching.
I’m adding it here because this is where you end up from google searching for umbraco and hmac.
Thanks @MattW , this is the answer for my case, and I’ll wager for OP too(?).
We had previously been using a ‘fallback’ like approach for any images that didn’t have a named crop to at least get some optimization by converting to .webp and applying a format value. This had been done in a taghelper used since v9 days.
The change to still use the same functionality but have the HMAC blessing was as easy as changing
Well thats awesome, I will test it out and if it works it will spare me a LOT of code. But I wonder why something like this completely absent from the documentation?
The documentation is a living and breathing thing which is also open source. Now that we know this is missing, I’m sure someone will find the time to add it. Feel free to click the “Edit on GitHub” button over there if you find something is missing.
Great, but no thanks. The ridiculous amount of hours spent figuring out how to do something as simple as showing an image in the backoffice, is enough as is. So I’m not spending more time picking up the slack and I doubt my manager will allow more time spent here anyway doing your work for you. Showing an image is a basic simple feature, something the developer should at some point have documented. We are several major versions into a post angular backoffice world, one would think the basics are covered, which they are not.
Fair enough — it’s an invitation, not an obligation.
The <umb-imaging-thumbnail> element is the intended way to do this. There’s a complete example of it in a custom block view over in this thread — different extension type than yours, but the imaging part works exactly the same in a property editor. You hand the element a media GUID and it takes care of the rest — resolving the GUID to an actual servable URL, the imaging repository calls, and the HMAC signing — so your component never needs to know how any of that works.
That’s really two gaps in the documentation: the GUID-to-URL resolution story for backoffice extensions in general, and the HMAC layer on top of it, which is new enough from the recent security work that no older examples account for it. We’ll cover both — I’ll link the docs here once they’re up.
Adding custom middleware to automatically serve images in WEBP format works great for images in the media library (/media) that are loaded using GetCropUrl(). Before HMAC this also worked for static images outside of /media, but when HMAC is enabled all static image URLs result in a 400 Bad Request when they’re being processed by the middleware. Is there a way to process static images with ImageSharp when HMAC is enabled?
The value of the HMAC changes based on the image parameters. To calculate it for a set of parameters, you can call on the IImageUrlGenerator, which by default is implemented by ImageSharpUrlGenerator.
You call GetImageUrl with your parameters, and you should be set.
Of course, it goes without saying that you can turn off HMAC entirely to allow any URL to be called. If you want to do that, you can delete the HMACSecretKey from appsettings.