-
Notifications
You must be signed in to change notification settings - Fork 412
/
Copy pathjwt.js
84 lines (73 loc) · 2.88 KB
/
jwt.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
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// @flow
// This file provides simple utils to deal with JWT tokens.
export function extractAndDecodePayload(jwtToken: string): any {
if (!isValidJwtToken(jwtToken)) {
console.error('The token is an invalid JWT token.');
return null;
}
try {
const payload = jwtToken.split('.')[1];
const decodedPayload = decodeJwtBase64Url(payload);
const jsonPayload = JSON.parse(decodedPayload);
return jsonPayload;
} catch (e) {
console.error(
`We got an unexpected error when trying to decode the JWT token '${jwtToken}':`,
e
);
return null;
}
}
// A JWT token is composed of 3 parts, separated by a period.
// These parts all use the base64url characters, that is base64 characters where
// "+" is replaced by "-", and "/" is replaced by "_". Moreover the padding
// character "=" isn't used with JWT.
// Here is an example:
// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiP34_fj9-In0.KIumXQmDxL1bJ0RGNV2-mm-8h0LEQATKbtHUsCHMGcg
// ╰ header ╰ payload ╰ signature
const JWT_TOKEN_RE =
/^(?:[a-zA-Z0-9_-])+\.(?:[a-zA-Z0-9_-])+\.(?:[a-zA-Z0-9_-])+$/;
export function isValidJwtToken(jwtToken: string): boolean {
return JWT_TOKEN_RE.test(jwtToken);
}
export function decodeJwtBase64Url(base64UrlEncodedValue: string): string {
// In the base64url variant used in JWT, the padding "=" character is removed.
// But atob doesn't mind, so we don't need to recover the missing padding like
// most implementations do.
// We do need to convert the string to a "normal" base64 encoding though.
const base64EncodedValue = base64UrlEncodedValue
.replace('-', '+')
.replace('_', '/');
return atob(base64EncodedValue);
}
/**
* This function returns a profile token from a JWT token, if the passed string
* looks like a JWT token. Otherwise it just returns the passed string because
* this would be the hash directly, as returned by a previous version of the
* server.
* In the future when the server will be migrated we'll be able to remove this
* fallback.
*/
export function extractProfileTokenFromJwt(hashOrToken: string): string {
if (isValidJwtToken(hashOrToken)) {
// This is a JWT token, let's extract the hash out of it.
const jwtPayload = extractAndDecodePayload(hashOrToken);
if (!jwtPayload) {
throw new Error(
`The JWT token that's been returned by the server is incorrect.`
);
}
const { profileToken } = jwtPayload;
if (!profileToken) {
throw new Error(
`The JWT token returned by the server doesn't contain a profile token.`
);
}
return profileToken;
}
// Then this is a good old hash.
return hashOrToken;
}