Token Authentication

Security

Token authentication gates CDN-delivered content with a signed, expiring URL, cookie or header. Your application signs the path and an expiry with a key the CDN holds; the edge recomputes the signature, checks the expiry against its own clock, and serves from cache without calling the origin.

Also known as Token Auth, Signed URL.

13 min read Updated Aug 30, 2026

Full Explanation

Token authentication gates access to content a CDN delivers. It puts a signature and a deadline into the request itself. Your application decides that someone is entitled to a file. It signs a chosen set of request elements, normally the path and an expiry time, with a key the CDN also holds. It then hands the signed URL, cookie or header to the client. An edge server recomputes the signature and checks the deadline against its own clock. Only then does it serve the object, from cache if it already has it. Google's Cloud CDN documentation puts the idea in one line: “A signed URL is a URL that provides limited permission and time to make a request.”

It is not an identity system. A JWT carries signed claims about a subject for a service to interpret. A CDN auth token authorises one path for one window instead. It says nothing about who is behind it. The real authentication happens in your application. It checks whether this person has logged in, paid, or finished a rental. Your application then mints the token. It is not confidentiality either. Akamai places Token Auth at level 1 of its content-protection spectrum, with geo restrictions, HTTPS delivery, media encryption and DRM stacked above it. So the bytes still travel in the clear unless you add TLS and encryption. It is also not protection for a directly reachable origin. A token the edge validates does nothing about a client that skips the edge.

The helicopter view: the authorisation decision moves to the edge. So private content becomes cacheable content. That is the whole reason the pattern exists in a CDN. Everything below is a consequence of it.

How it works

The signature is a message authentication code or a digital signature over data both sides can reconstruct. In the shared-secret form it is HMAC, defined in RFC 2104. Its abstract describes “HMAC, a mechanism for message authentication using cryptographic hash functions” that “can be used with any iterative cryptographic hash function … in combination with a secret shared key”. Origin and CDN each hold that key. So both can compute the same digest without talking to each other.

  1. Your application authorises the user by whatever rule applies: a session, a purchase, a licence check.
  2. It assembles the signed input: the path or path prefix, an expiry, and optionally a session identifier or client IP.
  3. It computes the signature. Cloudflare, Akamai and Google Cloud CDN use a shared secret with HMAC. Amazon CloudFront instead uses a key pair. You register public keys in a trusted key group. You then “use the corresponding private keys to sign the URLs”. CloudFront supports “RSA 2048 and ECDSA 256 key signatures”. So the edge needs no shared secret at all.
  4. The token is attached to the request. Akamai's documentation is explicit that the shape is a choice: “The completed token should be attached as a query string parameter, cookie, or request header”. That is why “signed URL” describes the most common form rather than the only one.
  5. The edge recomputes the signature with the same key and inputs. It then compares them. Cloud CDN documents exactly what it verifies: “The HTTP method is GET, HEAD, OPTIONS, or TRACE”, “The Expires parameter is set to a future time”, and “The request's signature matches the signature computed by using the named key”. “If any of these checks fails, a 403 Forbidden response is served.”
  6. On success the request proceeds normally. For CloudFront, once the signature is valid and the policy statement is satisfied, “CloudFront does the standard operations: determines whether the file is already in the edge cache, forwards the request to the origin if necessary, and returns the file to the user”. On failure nothing reaches your servers. Cloud CDN states that a request with a bad signature “is rejected and never goes to your backend for handling”. CloudFront states that “If the signature is invalid, the request is rejected”.

Two different timing models are in use. Confusing them is a common configuration error. Most platforms put the expiry in the token. Akamai's required start_time and end_time fields “set a time to live (TTL) for the token”. CloudFront and Cloud CDN carry an ending date and time too. Cloudflare's token authentication works differently. It signs the moment of issue and configures the lifetime at the edge. It accepts the token only while “http.request.timestamp.sec < (<TIMESTAMP_ISSUED> + 10800)”, a three-hour lifetime. Either way, the edge's own clock decides what “now” means.

What a token unlocks is decided by what you sign. Akamai's acl field “limits requesting client access to the specific URL or path set in the acl field”. Cloud CDN offers an optional URLPrefix parameter “allowing you to provide access to multiple URLs based on a common prefix”. A token signed over a wildcard is a token for everything.

Why it matters for a CDN

Gating without token authentication means asking the origin on every request whether this user may have this object. That is exactly the round trip a CDN exists to remove. Validating at the edge keeps the cache in play. The file is served locally when it is warm, and the origin is contacted only for a genuine miss. Cloud CDN goes further and rewrites cacheability for validly signed requests. Content the backend marks uncacheable is still cached, because Cloud CDN “overrides CDN-Cache-Control and standard Cache-Control headers when responding to requests that have valid signed URLs”. Cloud CDN still passes the backend's original headers to the client.

The catch is cache identity, and it is platform-specific. A signature that changes per user is a query string that changes per user. The query string is part of the cache key unless you say otherwise. Akamai's Cache Key Query Parameters behaviour exists so that “you can control whether the query string (or portions of it) are used to differentiate objects in cache”, including an option to exclude named parameters. Cloud CDN solves it by construction. “All valid signed requests for a particular base URL (the part before the Expires parameter) share the same cache entry”, although “Responses to signed and unsigned requests don't share cache entries”. Get this wrong on a platform that keys on the full query string, and every viewer becomes a cache miss.

For streaming the pattern is two-stage. That is because a player fetches one manifest and then thousands of segments. Akamai's Token Auth for Adaptive Media Delivery uses “hybrid tokens”. Your origin generates an access token, the “short token”. The player presents this short token with the request for the manifest. Once that validates, Akamai “automatically generates the session token after the access token is validated”. This session token is a long token, “valid for the duration of the media stream to protect stream elements delivered during the session”. It covers media keys, manifests and segments. The client returns it on each subsequent segment request. That is what makes per-segment authorisation affordable for HLS and DASH.

The commercial cases are the obvious ones and they are the documented ones. Cloudflare frames the feature as a way to “restrict access to documents, files, and media to select users without requiring them to register”. This “helps protect paid/restricted content from leeching and unauthorized sharing”. CloudFront points at movie rentals and music downloads: “You can distribute private content using a signed URL that is valid for only a short time—possibly for as little as a few minutes.” Software downloads, invoice PDFs, user uploads held in a private bucket, and paid video all have the same shape: many objects, high fan-out, per-user entitlement, and no wish to proxy the bytes through an application server.

What CDNs do

  • Cloudflare documents two options. One is a Worker that signs and verifies requests. The other is a WAF custom rule calling the Rules-language function is_timed_hmac_valid_v0(), with your secret, the request URI, the token lifetime, the request timestamp and the separator length. “Access to the is_timed_hmac_valid_v0() HMAC validation function requires a Cloudflare Pro, Business, or Enterprise plan.” The documented example rule blocks any visitor that fails validation on a given hostname and path.
  • Akamai has two implementations. It warns that “You can't use both token auth behaviors in the same rule”. For Adaptive Media Delivery, Token Authentication inside the Segmented Media Protection behaviour is the recommended route. It provides the access/session token pair. Elsewhere, Auth Token 2.0 Verification validates a token that is “a delimited list of string fields, with an HMAC to prevent tampering with the strings”. It is configured with a token location, a token name, a hexadecimal encryption key, and an action of either Verify and Deny or Just Verify. Advanced options cover the digest: “The algorithms from most to least secure are SHA256, SHA1, and MD5”. Akamai advises against changing the SHA256 default without a specific reason. Advanced options also add a salt, an input-escaping switch, and a transition key. Akamai publishes EdgeAuth token SDKs for C#, Go, Java, Node, Python and Ruby.
  • Amazon CloudFront offers signed URLs and signed cookies, under either a canned or a custom policy. A canned policy gives you an ending date and time. A custom policy adds a reusable resource pattern, an optional start time and an optional IP address or range, at the cost of a longer URL. Expiry is evaluated per request. CloudFront “checks the expiration date and time in a signed URL at the time of the HTTP request”. So a large download that begins just before expiry “should complete even if the expiration time passes during the download”. A range request issued after expiry fails.
  • Google Cloud CDN signs URLs or cookies with keys you create on a backend service or bucket, “up to three keys configured at a time”. It answers a bad signature with 403 at the edge without contacting the backend.
  • Fastly leaves the scheme to you. It documents the building blocks: a worked example in VCL, Rust, JavaScript and Go to “Make URLs expire after a configurable period”, and the VCL function digest.hmac_sha256 for computing the MAC at the edge.

Watch out for

  • The key is the entire security boundary. Cloud CDN says it plainly: “anyone who has one of your keys can create signed URLs or signed cookies that Cloud CDN accepts until the key is deleted from Cloud CDN”. Keys belong on the service that signs. They must never sit in client code. That service must not sign any path it is asked to.
  • There is no revocation before expiry. A leaked URL keeps working “until the expiration time for the URL is reached or the key used to sign the URL is rotated”. The expiry, not the login state, is your blast radius. Akamai's optional session identifier is the exception: it is what token-based access revocation needs.
  • An unsigned request may not be blocked at all. Cloud CDN “does not validate requests” that are unsigned. It “doesn't block requests without a Signature query parameter or Cloud-CDN-Cookie HTTP cookie”. It only rejects invalid ones. Removing public access from the bucket or origin is what closes that door.
  • A reachable origin defeats the whole scheme. AWS recommends requiring users to go through CloudFront URLs “to prevent users from bypassing the restrictions that you specify in signed URLs or signed cookies”. Google's guidance is that “Signed requests must always be validated at the origin before serving the response”. That is because origins serve a mix of signed and unsigned traffic, and clients can reach them directly.
  • The signed bytes must match byte for byte. Akamai exposes Escape token inputs and Ignore query string settings. Each “must match the setting used in your token generation code”. Cloudflare requires the Base64 MAC to be URL-encoded when the optional flags argument is not used. CloudFront is blunt about the failure mode: “If you add a query string to a signed URL after signing it, the URL returns an HTTP 403 status.”
  • Clock skew shifts the deadline. The edge judges expiry with its own time source. Cloudflare's rule, for example, compares against http.request.timestamp.sec. So a signer whose clock drifts issues tokens that die early or live longer than intended.
  • Binding a token to one IP breaks more than it fixes. Akamai's warning is direct: “Don't include the IP address field in your tokens to tie the token to a specific IP address, unless all requests will only come from that specific address. This can break delivery in a property if requests come from other IP addresses or if you're using an IPv4+IPv6 dual-stacked environment.” Mobile clients change address mid-session.
  • Cookie delivery has client limits. Akamai notes that token authentication “generally requires the use of browser cookies”. This “won't work if devices and browsers don't support cookies … typically the case with Apple Safari and HLS devices”. The documented answer is cookie-less Token in URI. It embeds the session token in the URL path instead. Cookie-based validation also requires that all stream elements sit on the same domain as the stream manifest.
  • Short tokens and device handoffs. Akamai documents that playback fails when a stream is moved between an iOS device and an Apple TV after the initial short token has expired. So the access-token lifetime has to allow for casting.

Best practice

  • Mint a token per request with the shortest lifetime the workflow tolerates. Cloud CDN's advice is to “set it to expire as soon as possible”. Do not copy a number out of a tutorial. CloudFront documents legitimate long-lived URLs for known audiences such as investors or employees. So the lifetime is a threat-model decision, not a default.
  • Sign only HTTPS URLs and distribute them over TLS. This is because plain HTTP exposes “the signature component of the signed URL” to interception.
  • Scope every token to the narrowest path that works, such as Akamai's acl or Cloud CDN's URLPrefix. Avoid a wildcard.
  • Overlap keys when rotating. Akamai's transition key is checked when the primary key fails, so that “users aren't denied access if you're rotating the primary key”. Cloud CDN allows three keys per backend. It suggests “periodically rotating your keys by deleting the oldest, adding a new key, and using the new key when signing URLs or cookies”.
  • Keep the signature out of the cache key, or run on a platform that already excludes it. This way one cached object serves every authorised viewer.
  • Restrict the origin independently: use private bucket access, an origin access control, or a shared secret header. This way the edge check is not the only check.
  • Keep SHA-256 as the digest. Treat the MD5 and SHA-1 options as legacy compatibility only.
  • Keep signer and edge clocks on NTP. Leave the expiry enough headroom to survive a slow start on a large object.

Examples

# Generate a signed URL (Python)
import hashlib, hmac, time

secret = b'your-cdn-secret-key'
path = '/premium/video.m3u8'
expiry = int(time.time()) + 3600  # 1 hour

message = f'{path}{expiry}'.encode()
sig = hmac.new(secret, message, hashlib.sha256).hexdigest()
url = f'https://cdn.example.com{path}?expires={expiry}&sig={sig}'

# Nginx: validate token
set $expected '';
set_hmac_sha256 $expected 'secret' $uri$arg_expires;
if ($arg_sig != $expected) { return 403; }
if ($arg_expires < $time_iso8601) { return 410; }

Frequently Asked Questions

Token authentication gates CDN-delivered content with a signed, expiring URL, cookie or header. Your application signs the path and an expiry with a key the CDN holds; the edge recomputes the signature, checks the expiry against its own clock, and serves from cache without calling the origin.

# Generate a signed URL (Python)
import hashlib, hmac, time

secret = b'your-cdn-secret-key'
path = '/premium/video.m3u8'
expiry = int(time.time()) + 3600  # 1 hour

message = f'{path}{expiry}'.encode()
sig = hmac.new(secret, message, hashlib.sha256).hexdigest()
url = f'https://cdn.example.com{path}?expires={expiry}&sig={sig}'

# Nginx: validate token
set $expected '';
set_hmac_sha256 $expected 'secret' $uri$arg_expires;
if ($arg_sig != $expected) { return 403; }
if ($arg_expires < $time_iso8601) { return 410; }

Yes. Token Authentication is also known as Token Auth, Signed URL. Token authentication gates CDN-delivered content with a signed, expiring URL, cookie or header. Your application signs the path and an expiry with a key the CDN holds; the edge recomputes the signature, checks the expiry against its own clock, and serves from cache without calling the origin.

Related CDN concepts include: