Secure Delivery

You can control who and when have access to files uploaded to your account. The functionality is provided by the Uploadcare feature called Authenticated URLs. When enabled, a user will require a token to access your content.

Token authentication also ensures a URL can only be accessed within a defined time span. Once a token expires, the content will no longer be accessible. To re-access the content, a new URL should be generated.

The Secure Delivery feature may be useful when:

  • Your users upload personal, medical or other sensitive data.
  • You want your content to be rendered by authorized users only.
  • You want users to access your content only within a specified time frame.

Authenticated URLs

Authenticated URLs work together with custom domains; you should set up a custom CNAME before using the feature. The format of an authenticated URL depends on a CDN provider your custom domain is connected to. We are currently working with Akamai and KeyCDN.

This is how authenticated URLs look like:

Akamai,

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

KeyCDN,

https://cdn.yourdomain.com/{uuid}/?token={token}&expire={timestamp}

Where:

  • cdn.yourdomain.com is your custom CNAME.
  • {uuid} is a unique file identifier or UUID.
  • {token} is a generated token used to access your content using a authenticated URL.
  • {timestamp} is an expiry date provided with the access token.

Note, {timestamp} must be defined as the Unix time when a provided token is set to expire.

Access tokens are generated on your backend. There is plenty of ready-made solutions for popular languages:

  • For Akamai (C, C#, Erlang, Go, Java, Perl, PHP, Python, Ruby)
  • For KeyCDN (PHP, Python, Ruby, NodeJS, Java)

Drop us a line in case you want to enable the Authenticated URLs feature for your account.

Use with File Uploader

Uploadcare allows you to implement a security-focused workflow via Authenticated URLs. That is, you will be able to control who and when have access to your content. To use the feature, you should first set the Custom CNAME.

When using Authenticated URLs, it is still okay to upload files to your project via the File Uploader UI. Showing image previews in the file uploader dialog becomes a bit more complicated, though. This section introduces the Authenticated URLs workflow and tells you about adequately handling image previews.

Authenticated URLs and Image Previews

Uploadcare File Uploader is an Upload API client. This means that every file uploaded using the file uploader dialog first goes to our upload instances, then storage, and finally CDN. The file uploader then gets that CDN URL and loads its content to render a preview. This works just fine when every CDN URL related to your Uploadcare account is public.

Once you enable the Authenticated URLs feature, the file uploader will not be able to show image previews because it’s unaware of your tokens. To handle this correctly, you will need a file uploader to proxy requests through your proxy backend.

Without using Authenticated URLs, the file uploader loads images directly from our CDN:

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

Enabling Authenticated URLs requires the file uploader to load images through your proxy backend:

-> (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}

The behavior described above is provided by the two file uploader options: previewProxy and previewUrlCallback. Depending on your use case, you can implement one or another.

Option previewProxy

Implementing the previewProxy option suits the following use cases:

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

In the case you do want to send extra data to your proxy backend, consider using the previewUrlCallback option instead. JWT tokens or image metadata are good examples of those extras.

To go with the previewProxy option, you are only required to specify a URL for your proxy backend endpoint. For instance:

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

Your file uploader will now load image previews via the following URL:

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

As you can see, it simply appends a query parameter holding the image preview URL to your previewProxy option, i.e.:

newPreviewUrl = previewProxy + 'url={previewUrl}'

By default, the uploader uses url as the query parameter name. However, you can also implement some different naming, e.g.:

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

Option previewUrlCallback

In case you want full control over the file uploader preview URLs, go with the previewUrlCallback option. The option gets assigned a function with a signature like:

(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}`
}

When you specify the previewUrlCallback option, previewProxy will be ignored. So, it’s either one option or another, not both.

Proxy Backend

The proxy backend is an API endpoint of your application.

It should be capable of doing the following:

  • Accept escaped preview URL as GET parameter.
  • Check user authorization.
  • Generate expired access tokens for that URL.
  • Append access tokens to the URL.
  • Send redirect to that URL.

The list above covers the basics; you can further extend it if you want.

Don’t forget to check user credentials on your backend. Make sure not to authenticate anonymous user requests, unless you want to.

Proxy Backend Example

Here is how your basic proxy backend could look like for Node.js,

app.get('/preview', (req, res) => {
  const url = req.query.url
  const user = req.user

  if (!user) {
    res.status(403).send('Authorization failed')
    return
  }

  const expire = Math.round(Date.now() / 1000) + 120
  const token = generateToken(url, expire)

  const secureUrl = url + `?token=${token}&expire=${expire}`

  res.redirect(secureUrl)
})