forked from bcnzer/cloudflare-worker-template-auth0-jwt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauth0-jwt-validation.js
98 lines (89 loc) · 3.58 KB
/
auth0-jwt-validation.js
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
* Following code is based on code found at https://blog.cloudflare.com/dronedeploy-and-cloudflare-workers/
* but has been modified to make it work for Auth0. Details here: https://liftcodeplay.com/2018/10/01/validating-auth0-jwts-on-the-edge-with-a-cloudflare-worker/
*/
/**
* Parse the JWT and validate it.
*
* We are just checking that the signature is valid, but you can do more that.
* For example, check that the payload has the expected entries or if the signature is expired..
*/
async function isValidJwt(request) {
const encodedToken = getJwt(request);
if (encodedToken === null) {
return false
}
const token = decodeJwt(encodedToken);
// Is the token expired?
let expiryDate = new Date(token.payload.exp * 1000)
let currentDate = new Date(Date.now())
if (expiryDate <= currentDate) {
console.log('expired token')
return false
}
return isValidJwtSignature(token)
}
/**
* For this example, the JWT is passed in as part of the Authorization header,
* after the Bearer scheme.
* Parse the JWT out of the header and return it.
*/
function getJwt(request) {
const authHeader = request.headers.get('Authorization');
if (!authHeader || authHeader.substring(0, 6) !== 'Bearer') {
return null
}
return authHeader.substring(6).trim()
}
/**
* Parse and decode a JWT.
* A JWT is three, base64 encoded, strings concatenated with ‘.’:
* a header, a payload, and the signature.
* The signature is “URL safe”, in that ‘/+’ characters have been replaced by ‘_-’
*
* Steps:
* 1. Split the token at the ‘.’ character
* 2. Base64 decode the individual parts
* 3. Retain the raw Bas64 encoded strings to verify the signature
*/
function decodeJwt(token) {
const parts = token.split('.');
const header = JSON.parse(atob(parts[0]));
const payload = JSON.parse(atob(parts[1]));
const signature = atob(parts[2].replace(/_/g, '/').replace(/-/g, '+'));
console.log(header)
return {
header: header,
payload: payload,
signature: signature,
raw: { header: parts[0], payload: parts[1], signature: parts[2] }
}
}
/**
* Validate the JWT.
*
* Steps:
* Reconstruct the signed message from the Base64 encoded strings.
* Load the RSA public key into the crypto library.
* Verify the signature with the message and the key.
*/
async function isValidJwtSignature(token) {
const encoder = new TextEncoder();
const data = encoder.encode([token.raw.header, token.raw.payload].join('.'));
const signature = new Uint8Array(Array.from(token.signature).map(c => c.charCodeAt(0)));
// You need to JWK data with whatever is your public RSA key. If you're using Auth0 you
// can download it from https://[your_domain].auth0.com/.well-known/jwks.json
// The following is setup with the data from an application www.wolftracker.nz
// The JWK is available here: https://wolftracker.au.auth0.com/.well-known/jwks.json
const jwk = {
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "-LvgjOXlvDfKtY6V-4j3OJbsh32IkD8GyNuCB1Egk5U",
"alg": "RS256",
"n": "owSQsO6k3lv2JWHyecafYkXPDw6uW-CmP4qeQGNR8-0elG86v5GafDHb1MAg76y9Ee-73HsEEIAVnTutDtO1sTQOWpnZWHsi21bXRlDiM1-bce6wW5BTVHwV5fDYsnNjlMrA0IJ4ltMFG8-crxmVP9wj7jOVIywYyW8q4qj_6Knuhei74edLv_xN4babo6cDMkL_-k3wMnVhni3sYhaJHNCrV892dmwROfREEScHP8bGpxMmp5VxmHI-nWCnmNGmsSuZcdRjMMVvzOSxZa0e3QvA4R5sqtCUr3X9xFmeLqmet8jcBCaWiA-7AR9Y_qep7Qom0ej2ITUOY7PRlKt4zQ"
}
const key = await crypto.subtle.importKey('jwk', jwk, { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' }, false, ['verify']);
return crypto.subtle.verify('RSASSA-PKCS1-v1_5', key, signature, data)
}
export default { isValidJwt }