Signed URLs
A signed url has a signature in its query. Nobody can change the url without the APP_KEY.
Use it for links in emails, like "unsubscribe" or "download your file", where the user is not logged in.
Make a signed url
Give the route a name and add the ValidateSignature middleware:
Route.get('/unsubscribe/{user}', <dynamic>[
const ValidateSignature(),
(UserController c) => c.unsubscribe,
]).name('unsubscribe');
Then make the url with Route.signedUrl:
String url = Route.signedUrl(
'unsubscribe',
params: <String, Object>{'user': 5},
);
// https://example.com/unsubscribe/5?signature=3f9a...
A url with no signature, a wrong one, or a changed path or query gets 403 Forbidden.
A url that expires
Give expires. The url gets an expires query param (unix seconds), and it is signed too.
After that time the url gets 403.
String url = Route.signedUrl(
'download',
params: <String, Object>{'file': 12},
expires: Duration(hours: 1),
);
Absolute and relative urls
By default the url is absolute. Dox puts APP_URL from the env in front, like https://example.com. The scheme and host are signed too.
Give baseUrl: to use another one.
- The
Hostof the request must be the host ofAPP_URL, with the same port. - The scheme must match too. Behind a proxy that ends TLS, add the proxy to
AppConfig.trustedProxies, so Dox readsX-Forwarded-Proto: https.
With absolute: false, only the path and the query are signed. Check it with ValidateSignature(absolute: false):
Route.get('/files/{id}', <dynamic>[
const ValidateSignature(absolute: false),
(FileController c) => c.show,
]).name('files.show');
String url = Route.signedUrl(
'files.show',
params: <String, Object>{'id': 3},
absolute: false,
);
// /files/3?signature=...
Check in a controller
ValidateSignature.hasValidSignature(req) gives true or false, so you can answer in your own way:
How it works
- The signature is HMAC-SHA256 of the url, with a key made from
APP_KEY(KeyDerivation.signedUrl). - Dox compares it in constant time.
- After you change
APP_KEY, urls made with an old key still work when the old key is inAppConfig.previousKeys. signatureis a reserved query param. Any other param added to a signed url makes it invalid.