Signed URLs (Secure delivery)

Control who and for how long can access files in your project via Signed URLs. When enabled, a user will require a token to access your content by the link like this:

https://cdn.yourdomain.com/{uuid}/?token=exp={timestamp}~hmac={token}

A signed URL is a URL that contains authentication information in its query string that provides limited permission and time to get the file.

Use cases

When to use Signed URLs:

  • End-users upload personal, medical, and other sensitive data.
  • Only an authorized client can access certain content.
  • Limit content access by time.

How Signed URLs works

Contact us to enable the Secure delivery feature. Please specify if you need to upload files larger than 1GB in your request. Secure delivery only works on paid plans. Prior to using Secure delivery, set up a custom CNAME.

An example is:

https://cdn.yourdomain.com/{uuid}/?token=exp={timestamp}~acl={acl}~hmac={token}
  • {uuid} is a UUID of any file in your Uploadcare project or a URI (UUID + transformations + filename), which is a URL part.
  • {acl} is an optional Access Control List parameter. It supports wildcards (*, ?). Also, it can be a string (single path) or an array (multi-paths).

ACL examples to access files with a token:

  • acl=/*/ – any file in a project.
  • acl=/{uuid}/ – original file with UUID.
  • acl=/{uuid}/-/resize/640x/ – modified file version.

Token generation

Your backend app should take care of generating access tokens. To create tokens, you need to get the encryption key from our support.

We recommend that you start with ready-made solutions for popular languages:

Here non-official solutions:

You can use signed URLs into the Uploadcare PHP library.

After setting up signed URLs, specify the projects where you plan to store protected files. We will close public access to these projects.

Proxy backend example

The proxy backend is an API endpoint of your application. The app needs to resolve the following tasks:

  • Accept escaped preview URL as a GET parameter.
  • Check user authorization.
  • Generate expiring access tokens for that URL.
  • Append access tokens to the URL.
  • Redirect to that URL.

Don't forget to check user credentials on your backend. Make sure not to authenticate anonymous user requests. Otherwise using Secure delivey don't make any sense.

Here is a previewProxy example (Node JS + Express):

const express = require("express");
const cookieParser = require("cookie-parser");
const EdgeAuth = require("akamai-edgeauth");

// User's custom CDN domain
const HOSTNAME = "https://files.acme.com";
// Encryption key for the above domain
const EA_ENCRYPTION_KEY = "your encryption key";
// token lifetime in seconds
const DURATION = 500;

const ea = new EdgeAuth({
	key: EA_ENCRYPTION_KEY,
	windowSeconds: DURATION,
	tokenName: "token",
	escapeEarly: true,
});

const app = express();

app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());

app.get("/preview", (req, res) => {
	const user = req.cookies.user;
	if (!user) {
		return res.status(403).send("Authorization failed");
	}
	const { pathname } = new URL(req.query.url);
	const token = ea.generateURLToken(pathname);
	const signedURL = `${HOSTNAME}${pathname}?${ea.options.tokenName}=${token}`;
	res.redirect(signedURL);
});

const listener = app.listen(3000, () => {
	console.log("Listening on port " + listener.address().port);
});javascript

Show image previews in File uploader

After uploading, File uploader loads image previews from the CDN:

-> (GET) https://ucarecdn.com/{uuid}/

With Secure delivery on, File Upload can't show previews because Signed URLs include a token part. To work that around, you can load images through a proxy backend, where it can hook up the token info:

-> (GET) https://domain.com/preview?url=https%3A%2F%2Fcdn.domain.com%2F{uuid}%2F
-> (Redirect) https://cdn.domain.com/{uuid}/?token={token}&expire={expire}

Here are two options that can help you show image previews over Secure delivery:

Option previewProxy

Implementing the previewProxy option works best for these cases:

  • Your application uses cookie-based authorization.
  • Your proxy backend and your app are located in the same domain (otherwise, cookies won't be sent).
  • You don't need any other image-related data beside URLs.

To use previewProxy option, specify your proxy backend endpoint URL, and you're good to go:

UPLOADCARE_PREVIEW_PROXY = 'https://domain.com/preview?'javascript

It'll let File uploader load image previews via the following URL:

https://domain.com/preview?url=https%3A%2F%2Fcdn.domain.com%2F{uuid}%2F

It appends a query parameter with image preview URL to previewProxy:

newPreviewUrl = previewProxy + 'url={previewUrl}'javascript

By default, the uploader uses url as the query parameter name, but you can have a custom naming as well:

'https://domain.com/preview?' + 'url={previewUrl}'
'https://domain.com/preview?foo=bar' + '&url={previewUrl}'
'https://domain.com/preview?foo=bar&myUrl=' + '{previewUrl}'javascript

Option previewUrlCallback

This option provides you with explicit control over the File uploader preview URLs. In code, previewUrlCallback is a function with a signature:

(previewUrl, fileInfo) => previewUrl

Example:

UPLOADCARE_PREVIEW_URL_CALLBACK = function(previewUrl, fileInfo) {
    const jwtToken = getJWTToken()
    return `https://domain.com/preview?` +
      `url=${encodeURIComponent(previewUrl)}&` +
      `uuid=${fileInfo.uuid}&` +
      `token=${jwtToken}`
}javascript

Note, previewUrlCallback overrides previewProxy, and the latter option will be ignored.