Enabling URL token validation
Last updated 2021-06-30
Token validation allows you to create URLs that expire. Tokens are generated within your web application and appended to URLs in a query string. Requests are authenticated at Fastly's edge instead of your origin server. When Fastly receives a request for the URL, the token is validated before serving the content. After a configurable period of time, the token expires.
Adding custom VCL
To enable token validation, you'll need to create a Varnish configuration named vcl_recv
and add the following example code to it.
You can also use the custom VCL and Compute@Edge examples in our time-limited URL tokens documentation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# only do this once per request
if (fastly.ff.visits_this_service == 0 && req.restarts == 0) {
declare local var.token STRING;
declare local var.token_expiration STRING;
declare local var.token_signature STRING;
declare local var.to_sign STRING;
# extract and remove the token
set var.token = querystring.get(req.url, "token");
set req.url = querystring.filter(req.url, "token");
# make sure there is a token
if (var.token == "") {
error 403;
}
# make sure there is a valid expiration and signature
if (var.token !~ "^(\d{10,11})_([a-f0-9]{40})$") {
error 403;
}
# extract token expiration and signature
set var.token_expiration = re.group.1;
set var.token_signature = re.group.2;
# calculate string to sign
set var.to_sign = req.url + var.token_expiration;
# make sure the signature is valid
if (!digest.secure_is_equal(var.token_signature, regsub(digest.hmac_sha1(digest.base64_decode("YOUR%SECRET%KEY%IN%BASE64%HERE"), var.to_sign), "^0x", ""))) {
error 403;
}
# make sure the expiration time has not elapsed
if (time.is_after(now, std.integer2time(std.atoi(var.token_expiration)))) {
error 410;
}
}
Be sure to generate your own key for use with this VCL (the example key shown here will intentionally cause an error). Due to limitations in VCL, the binary form of the key should not contain NUL (0x00) bytes. In Linux, use the command:
1
$ while (b=$(openssl rand -base64 32) ; echo $b; echo $b | base64 -d | hd | grep " 00 " > /dev/null); do :; done | tail -1
In macOS, use the command:
1
$ while (b=$(openssl rand -base64 32) ; echo $b; echo $b | base64 -D | hexdump | grep " 00 " > /dev/null); do :; done | tail -1
The custom VCL code above checks for two things:
- It verifies the signature supplied matches the signature of the token
- It ensures the current time is less than the expiration time specified in the token
If the signature is invalid, Varnish returns a 403 response. If the signature is valid but the expiration time has elapsed, Varnish returns a 410 response. The different response codes are helpful for debugging.
The token information
A token is expected in the ?token=
GET parameter. Tokens take the format [expiration]_[signature]
and look like this:
1
1441307151_4492f25946a2e8e1414a8bb53dab8a6ba1cf4615
The full request URL with the token looks like this:
1
http://www.example.com/foo/bar.html?token=1441307151_4492f25946a2e8e1414a8bb53dab8a6ba1cf4615
The signature validation
The key found in digest.hmac_sha1
can be any string. The one in this example was generated with the following command:
1
$ openssl rand -base64 32
The example key YOUR%SECRET%KEY%IN%BASE64%HERE
will intentionally cause an error if you use it. You must replace it with your own randomly generated secret key.
Anyone who learns your key can bypass your token validation, so it's critical that you keep it secret.
Configuring your application
You'll need to write custom code in your application to generate tokens and authenticate with Varnish. We provide examples in our token functions repository on GitHub. Review the examples in the repository to learn how to generate custom tokens within your application.
Testing
To test your configuration, append a token generated by your application to a URL in a query string. For example:
http://www.example.com/foo/bar.html?token=1441307151_4492f25946a2e8e1414a8bb53dab8a6ba1cf4615
If the token is valid, you will receive a normal response. If it is invalid, you will receive a 403 response.
Troubleshooting NUL bytes
You should verify that your secret key is devoid of NUL bytes. If the Base64-decoded string contains a NUL byte (0x00), then that byte and any bytes following it will not be included in the response. See Base64 decoding for more information.