Edgio

JWT Validation

You may only deploy this edge function using CDN-as-Code due to Node.js dependencies. It will not work when deployed through the Edgio Console.
This example uses Edge Functions to validate a JSON Web Token (JWT) sent by a client. Handling this validation at the edge can help to offload the work from the origin server, and offer a more secure and efficient way to verify the token. Additionally, you can extend this edge function to check whether the client is authorized to access a protected resource or to verify the client’s identity.

Router Configuration

In the Edgio router, you can use the edge_function feature to specify the path to the edge function that will handle the JWT validation.
JavaScriptroutes.js
1import {Router, edgioRoutes} from '@edgio/core';
2
3export default new Router().use(edgioRoutes).post('/jwt', {
4 edge_function: './edge-functions/validate.js',
5});

Edge Function

This edge function uses the jsrsasign libary to validate a JWT signed with a HS256, HS384, or HS512 algorithm. It expects to receive a POST request with the following JSON payload:
  • token: Required. This parameter must be set to the JWT that will be validated.
  • pubKey: By default, the JWT will be decoded using a default signing key (i.e., your-256-bit-secret) defined within the JWT_SECRET environment variable. However, you may decode it using a custom signing key by defining a pubKey parameter.
    This example allows you to pass a signing key to make it easier to test JWT validation through this edge function. However, signing keys should be kept secret. For example, a client should not pass a signing key within the request payload.
Upon completion, this edge function will report the result in the response.
Sample curl request:
Bash
1curl -X POST -d '{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"}' https://edgio-community-examples-v7-ef-jwt-validation-live.glb.edgio.link/jwt
Sample response:
{"valid":true,"alg":"HS256","payload":{"sub":"1234567890","name":"John Doe","iat":1516239022}}
Alternatively, you can validate JWTs by submitting the form on the following web page:
https://edgio-community-examples-v7-ef-jwt-validation-live.glb.edgio.link/

Code

This edge function’s code:
JavaScriptedge-functions/validate.js
1import { KJUR, KEYUTIL } from 'jsrsasign'
2import { Buffer } from 'buffer'
3
4// Set up some polyfills to allow this code to run locally and when deployed:
5global.process = global.process || { env: {} }
6const fromBase64 = (str) => Buffer.from(str, 'base64').toString()
7
8export async function handleHttpRequest(request, context) {
9 Object.assign(process.env, context.environmentVars)
10
11 // Extract the token and any other objects from the request.
12 const { token, ...other } = await request.json()
13
14 // Split out the header and payload from the cleartext token and determine the right algorithm to use.
15 const [header, payload] = token.split('.')
16 const { alg } = JSON.parse(fromBase64(header))
17
18 let validationComponent = null
19 let valid = false
20 const resp = { valid }
21
22 try {
23 // For HSxxx algorithms, the validation requires a plaintext secret key.
24 // For RSxxx, ESxxx, and PSxxx algorithms, a public key is required instead.
25 // The public key is expected to be part of the request payload and be named pubKey;
26 // the secret key SHOULD NOT be part of the payload.
27 // Note that for demo purposes (being able to set an arbitrary signing key) this
28 // version of the EF will use the secret from `pubKey` if it exists.
29 if (/^HS/i.test(alg)) {
30 if ('pubKey' in other) {
31 validationComponent = other.pubKey
32 } else {
33 validationComponent = process.env.JWT_SECRET
34 }
35 } else if (/^[REP]S/i.test(alg)) {
36 validationComponent = KEYUTIL.getKey(other.pubKey)
37 } else {
38 return new Response('Invalid JWT alg specified.', { status: 401 })
39 }
40
41 valid = KJUR.jws.JWS.verifyJWT(token, validationComponent, { alg: [alg] })
42 if (valid === true) {
43 // Only parse the payload if the signature is valid.
44 const decodedPayload = JSON.parse(fromBase64(payload))
45 Object.assign(resp, { valid, alg, payload: decodedPayload })
46 }
47 } catch (e) {
48 // Handle exceptions here.
49 }
50
51 return new Response(JSON.stringify(resp), {
52 status: valid ? 200 : 401
53 })
54}