@astronautlabs/jwt 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +107 -0
- package/demo.key +27 -0
- package/demo8.key +28 -0
- package/dist/browser/base64url.d.ts +4 -0
- package/dist/browser/base64url.js +18 -0
- package/dist/browser/base64url.js.map +1 -0
- package/dist/browser/index.d.ts +5 -0
- package/dist/browser/index.js +21 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/utils.d.ts +6 -0
- package/dist/browser/utils.js +24 -0
- package/dist/browser/utils.js.map +1 -0
- package/dist/browser/webcrypto-jwt.d.ts +22 -0
- package/dist/browser/webcrypto-jwt.js +378 -0
- package/dist/browser/webcrypto-jwt.js.map +1 -0
- package/dist/browser/webcrypto-jwt.test.d.ts +1 -0
- package/dist/browser/webcrypto-jwt.test.js +6 -0
- package/dist/browser/webcrypto-jwt.test.js.map +1 -0
- package/dist/common/expiry.d.ts +1 -0
- package/dist/common/expiry.js +25 -0
- package/dist/common/expiry.js.map +1 -0
- package/dist/common/index.d.ts +2 -0
- package/dist/common/index.js +15 -0
- package/dist/common/index.js.map +1 -0
- package/dist/common/interface.d.ts +38 -0
- package/dist/common/interface.js +3 -0
- package/dist/common/interface.js.map +1 -0
- package/dist/engine.test.d.ts +10 -0
- package/dist/engine.test.js +295 -0
- package/dist/engine.test.js.map +1 -0
- package/dist/fixtures/es256.fixture.d.ts +6 -0
- package/dist/fixtures/es256.fixture.js +10 -0
- package/dist/fixtures/es256.fixture.js.map +1 -0
- package/dist/fixtures/hs256.fixture.d.ts +6 -0
- package/dist/fixtures/hs256.fixture.js +10 -0
- package/dist/fixtures/hs256.fixture.js.map +1 -0
- package/dist/fixtures/hs384.fixture.d.ts +6 -0
- package/dist/fixtures/hs384.fixture.js +10 -0
- package/dist/fixtures/hs384.fixture.js.map +1 -0
- package/dist/fixtures/hs512.fixture.d.ts +6 -0
- package/dist/fixtures/hs512.fixture.js +10 -0
- package/dist/fixtures/hs512.fixture.js.map +1 -0
- package/dist/fixtures/rs256.fixture.d.ts +6 -0
- package/dist/fixtures/rs256.fixture.js +10 -0
- package/dist/fixtures/rs256.fixture.js.map +1 -0
- package/dist/fixtures/rs512.fixture.d.ts +6 -0
- package/dist/fixtures/rs512.fixture.js +10 -0
- package/dist/fixtures/rs512.fixture.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/node/engine.test.d.ts +1 -0
- package/dist/node/engine.test.js +6 -0
- package/dist/node/engine.test.js.map +1 -0
- package/dist/node/index.d.ts +9 -0
- package/dist/node/index.js +117 -0
- package/dist/node/index.js.map +1 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +9 -0
- package/dist/test.js.map +1 -0
- package/karma.conf.ts +59 -0
- package/package.json +46 -0
- package/src/browser/base64url.ts +12 -0
- package/src/browser/index.ts +6 -0
- package/src/browser/utils.ts +20 -0
- package/src/browser/webcrypto-jwt.test.ts +4 -0
- package/src/browser/webcrypto-jwt.ts +351 -0
- package/src/common/expiry.ts +25 -0
- package/src/common/index.ts +2 -0
- package/src/common/interface.ts +47 -0
- package/src/engine.test.ts +173 -0
- package/src/fixtures/es256.fixture.ts +25 -0
- package/src/fixtures/hs256.fixture.ts +6 -0
- package/src/fixtures/hs384.fixture.ts +6 -0
- package/src/fixtures/hs512.fixture.ts +6 -0
- package/src/fixtures/rs256.fixture.ts +81 -0
- package/src/fixtures/rs512.fixture.ts +81 -0
- package/src/index.ts +5 -0
- package/src/node/engine.test.ts +4 -0
- package/src/node/index.ts +56 -0
- package/src/test.ts +7 -0
- package/tsconfig.json +37 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Base64URL } from "./base64url";
|
|
2
|
+
|
|
3
|
+
export class Utils {
|
|
4
|
+
public static isString(s) {
|
|
5
|
+
return typeof s === 'string';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
public static utf8ToUint8Array(str) {
|
|
9
|
+
str = btoa(unescape(encodeURIComponent(str)));
|
|
10
|
+
return Base64URL.parse(str);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public static isFunction(fn) {
|
|
14
|
+
return typeof fn === 'function';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public static isObject(arg) {
|
|
18
|
+
return arg !== null && typeof arg === 'object';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
// Originally from https://github.com/pose/webcrypto-jwt
|
|
2
|
+
// (C) Copyright (c) 2015 Alberto Pose albertopose@gmail.com
|
|
3
|
+
// Used under the terms of the MIT License (https://github.com/pose/webcrypto-jwt/blob/master/LICENSE.md)
|
|
4
|
+
|
|
5
|
+
import { JWTEngine, EncodeOptions, Token, DecodeOptions, Options, DecodedToken } from "../common/interface";
|
|
6
|
+
import { Base64URL } from "./base64url";
|
|
7
|
+
import { Utils } from "./utils";
|
|
8
|
+
import { validateExpiry } from "../common";
|
|
9
|
+
|
|
10
|
+
const ALGORITHMS = {
|
|
11
|
+
none: {},
|
|
12
|
+
HS256: {
|
|
13
|
+
importKey: {
|
|
14
|
+
name: 'HMAC',
|
|
15
|
+
hash: 'SHA-256'
|
|
16
|
+
},
|
|
17
|
+
operation: {
|
|
18
|
+
name: 'HMAC',
|
|
19
|
+
hash: 'SHA-256'
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
HS384: {
|
|
23
|
+
importKey: {
|
|
24
|
+
name: 'HMAC',
|
|
25
|
+
hash: 'SHA-384'
|
|
26
|
+
},
|
|
27
|
+
operation: {
|
|
28
|
+
name: 'HMAC',
|
|
29
|
+
hash: 'SHA-384'
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
HS512: {
|
|
33
|
+
importKey: {
|
|
34
|
+
name: 'HMAC',
|
|
35
|
+
hash: 'SHA-512'
|
|
36
|
+
},
|
|
37
|
+
operation: {
|
|
38
|
+
name: 'HMAC',
|
|
39
|
+
hash: 'SHA-512'
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
RS256: {
|
|
43
|
+
importKey: {
|
|
44
|
+
name: 'RSASSA-PKCS1-v1_5',
|
|
45
|
+
hash: 'SHA-256'
|
|
46
|
+
},
|
|
47
|
+
operation: {
|
|
48
|
+
name: 'RSASSA-PKCS1-v1_5',
|
|
49
|
+
hash: 'SHA-256'
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
RS512: {
|
|
53
|
+
importKey: {
|
|
54
|
+
name: 'RSASSA-PKCS1-v1_5',
|
|
55
|
+
hash: 'SHA-512'
|
|
56
|
+
},
|
|
57
|
+
operation: {
|
|
58
|
+
name: 'RSASSA-PKCS1-v1_5',
|
|
59
|
+
hash: 'SHA-512'
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
ES256: {
|
|
63
|
+
importKey: {
|
|
64
|
+
name: 'ECDSA',
|
|
65
|
+
namedCurve: 'P-256'
|
|
66
|
+
},
|
|
67
|
+
operation: {
|
|
68
|
+
name: 'ECDSA',
|
|
69
|
+
namedCurve: 'P-256',
|
|
70
|
+
hash: 'SHA-256'
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export class WebCryptoJWT implements JWTEngine {
|
|
76
|
+
constructor(
|
|
77
|
+
private subtleCrypto? : SubtleCrypto
|
|
78
|
+
) {
|
|
79
|
+
if (!subtleCrypto)
|
|
80
|
+
this.findSubtleCrypto();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async decodeUntrusted(token: string): Promise<Token> {
|
|
84
|
+
let decodedToken = this._decode(token);
|
|
85
|
+
return { claims: decodedToken.payload, string: token };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private findSubtleCrypto() {
|
|
89
|
+
if ('crypto' in window)
|
|
90
|
+
this.subtleCrypto = crypto.subtle || crypto['webkitSubtle'];
|
|
91
|
+
if (!this.subtleCrypto && 'msCrypto' in window)
|
|
92
|
+
this.subtleCrypto = window['msCrypto'].Subtle;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
async encode(payload: Record<string, any>, options: EncodeOptions): Promise<Token> {
|
|
97
|
+
return {
|
|
98
|
+
string: await this._sign(payload, options.secretOrKey, this.algorithmOf(options)),
|
|
99
|
+
claims: payload
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async validate(string: string, options: DecodeOptions): Promise<Token> {
|
|
104
|
+
let decodedToken = this._decode(string);
|
|
105
|
+
let algorithm = this.algorithmOf(options);
|
|
106
|
+
let secretOrKey = options.secretOrKey;
|
|
107
|
+
let claims = decodedToken.payload;
|
|
108
|
+
|
|
109
|
+
// Signature must match
|
|
110
|
+
|
|
111
|
+
if (decodedToken.header.alg !== algorithm)
|
|
112
|
+
throw new Error(`Cannot validate JWT '${string}': Token has incorrect algorithm`);
|
|
113
|
+
|
|
114
|
+
if (algorithm !== 'none' && !(await this._verify(decodedToken, secretOrKey, algorithm)))
|
|
115
|
+
throw new Error(`Cannot validate JWT '${string}': Invalid signature`);
|
|
116
|
+
|
|
117
|
+
// Algorithm must match
|
|
118
|
+
|
|
119
|
+
// Expiration
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
validateExpiry(claims.exp, options.now, options.validate?.exp);
|
|
123
|
+
} catch (e) {
|
|
124
|
+
throw new Error(`Cannot validate JWT '${string}': ${e.message}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
string,
|
|
129
|
+
claims: decodedToken.payload
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private algorithmOf(options : Options) {
|
|
134
|
+
return options.algorithm || 'HS256';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private str2ab(str : string) {
|
|
138
|
+
const buf = new ArrayBuffer(str.length);
|
|
139
|
+
const bufView = new Uint8Array(buf);
|
|
140
|
+
for (let i = 0, strLen = str.length; i < strLen; i++) {
|
|
141
|
+
bufView[i] = str.charCodeAt(i);
|
|
142
|
+
}
|
|
143
|
+
return buf;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Adapted from https://chromium.googlesource.com/chromium/blink/+/master/LayoutTests/crypto/subtle/hmac/sign-verify.html
|
|
148
|
+
*
|
|
149
|
+
* @param token
|
|
150
|
+
* @param secret
|
|
151
|
+
* @param alg
|
|
152
|
+
*/
|
|
153
|
+
private async _verify(token : DecodedToken, secret : string, alg : string): Promise<boolean> {
|
|
154
|
+
if (alg === 'none')
|
|
155
|
+
return true;
|
|
156
|
+
|
|
157
|
+
let importAlgorithm = ALGORITHMS[alg];
|
|
158
|
+
if (!importAlgorithm)
|
|
159
|
+
throw new Error(`Algorithm ${alg} is not supported`);
|
|
160
|
+
|
|
161
|
+
let keyFormat : string;
|
|
162
|
+
let secretBuf : ArrayBuffer;
|
|
163
|
+
let encoder = new TextEncoder();
|
|
164
|
+
|
|
165
|
+
// TODO Test utf8ToUint8Array function
|
|
166
|
+
if (secret.includes('-----BEGIN PUBLIC KEY-----')) {
|
|
167
|
+
secretBuf = this.str2ab(atob(
|
|
168
|
+
secret
|
|
169
|
+
.replace(/^-----BEGIN PUBLIC KEY-----\n/, '')
|
|
170
|
+
.replace(/\n-----END PUBLIC KEY-----/, '')
|
|
171
|
+
.replace(/\n/g, '')
|
|
172
|
+
));
|
|
173
|
+
keyFormat = 'spki';
|
|
174
|
+
} else if (secret.includes('-----BEGIN RSA PUBLIC KEY-----')) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
`PKCS#1 keys are not supported. `
|
|
177
|
+
+ `Please convert the key to PKCS#8 instead: `
|
|
178
|
+
+ `openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in pkcs1.key -out pkcs8.key`
|
|
179
|
+
);
|
|
180
|
+
} else {
|
|
181
|
+
secretBuf = encoder.encode(secret);
|
|
182
|
+
keyFormat = 'raw';
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
let key : CryptoKey;
|
|
186
|
+
|
|
187
|
+
if (!this.subtleCrypto)
|
|
188
|
+
throw new Error(`Not supported: No Subtle Crypto support`);
|
|
189
|
+
|
|
190
|
+
try {
|
|
191
|
+
key = await this.subtleCrypto.importKey(
|
|
192
|
+
keyFormat,
|
|
193
|
+
secretBuf,
|
|
194
|
+
importAlgorithm.importKey,
|
|
195
|
+
false,
|
|
196
|
+
['verify']
|
|
197
|
+
);
|
|
198
|
+
} catch (e) {
|
|
199
|
+
let identifier = `jwtUncaughtError${Math.floor(10000 + Math.random() * 10000)}`;
|
|
200
|
+
|
|
201
|
+
console.error(`JWT.verify(): Caught error while importing ${alg} key: format=${keyFormat}, importAlgorithm: ${JSON.stringify(importAlgorithm.importKey)}.`);
|
|
202
|
+
console.error(e);
|
|
203
|
+
|
|
204
|
+
if (typeof window !== 'undefined') {
|
|
205
|
+
window[identifier] = e;
|
|
206
|
+
console.error(`To aid in debugging, this error was saved to ${identifier}`);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
throw e;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
let partialToken = `${token.encodedHeader}.${token.encodedPayload}`;
|
|
213
|
+
let signaturePart = token.signature;
|
|
214
|
+
|
|
215
|
+
// TODO Test utf8ToUint8Array function
|
|
216
|
+
let messageAsUint8Array = encoder.encode(partialToken);
|
|
217
|
+
// TODO Test utf8ToUint8Array function
|
|
218
|
+
let signatureAsUint8Array = Base64URL.parse(signaturePart);
|
|
219
|
+
|
|
220
|
+
if (!this.subtleCrypto)
|
|
221
|
+
throw new Error(`Not supported: No Subtle Crypto support`);
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
return await this.subtleCrypto.verify(
|
|
225
|
+
importAlgorithm.operation,
|
|
226
|
+
key,
|
|
227
|
+
signatureAsUint8Array,
|
|
228
|
+
messageAsUint8Array
|
|
229
|
+
);
|
|
230
|
+
} catch (e) {
|
|
231
|
+
console.error(`JWT.verify(): Caught error while verifying token:`);
|
|
232
|
+
console.error(e);
|
|
233
|
+
throw e;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
private async _sign(payload : Record<string,any>, secret : string, alg : string): Promise<string> {
|
|
238
|
+
let importAlgorithm = ALGORITHMS[alg];
|
|
239
|
+
if (!importAlgorithm)
|
|
240
|
+
throw new Error(`Algorithm '${alg}' is not supported`);
|
|
241
|
+
|
|
242
|
+
let payloadAsJSON = JSON.stringify(payload);
|
|
243
|
+
let header = { alg: alg, typ: 'JWT' };
|
|
244
|
+
let headerAsJSON = JSON.stringify(header);
|
|
245
|
+
let partialToken = Base64URL.stringify(Utils.utf8ToUint8Array(headerAsJSON)) + '.' +
|
|
246
|
+
Base64URL.stringify(Utils.utf8ToUint8Array(payloadAsJSON));
|
|
247
|
+
|
|
248
|
+
if (alg === 'none')
|
|
249
|
+
return `${partialToken}.`;
|
|
250
|
+
|
|
251
|
+
let keyFormat = 'raw';
|
|
252
|
+
let encoder = new TextEncoder();
|
|
253
|
+
let secretBuf : ArrayBuffer;
|
|
254
|
+
|
|
255
|
+
// TODO Test utf8ToUint8Array function
|
|
256
|
+
if (secret.includes('-----BEGIN RSA PRIVATE KEY-----')) {
|
|
257
|
+
throw new Error(`PKCS#1 keys are not supported. Please convert the key to PKCS#8 instead: openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in pkcs1.key -out pkcs8.key`);
|
|
258
|
+
} else if (secret.includes('-----BEGIN PRIVATE KEY-----')) {
|
|
259
|
+
secretBuf = this.str2ab(atob(
|
|
260
|
+
secret
|
|
261
|
+
.replace(/^-----BEGIN PRIVATE KEY-----\n/, '')
|
|
262
|
+
.replace(/\n-----END PRIVATE KEY-----/, '')
|
|
263
|
+
.replace(/\n/g, '')
|
|
264
|
+
));
|
|
265
|
+
keyFormat = 'pkcs8';
|
|
266
|
+
} else {
|
|
267
|
+
secretBuf = encoder.encode(secret);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
if (!this.subtleCrypto)
|
|
272
|
+
throw new Error(`Not supported: No Subtle Crypto support`);
|
|
273
|
+
|
|
274
|
+
let key : CryptoKey;
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
key = await this.subtleCrypto.importKey(
|
|
278
|
+
keyFormat,
|
|
279
|
+
secretBuf,
|
|
280
|
+
importAlgorithm.importKey,
|
|
281
|
+
false,
|
|
282
|
+
['sign']
|
|
283
|
+
)
|
|
284
|
+
} catch (e) {
|
|
285
|
+
console.error(`JWT.sign(): Caught error while importing ${alg} key: format=${keyFormat}, importAlgorithm: ${JSON.stringify(importAlgorithm.importKey)}`);
|
|
286
|
+
console.error(e);
|
|
287
|
+
throw e;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
let messageAsUint8Array = Utils.utf8ToUint8Array(partialToken);
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
if (!this.subtleCrypto)
|
|
294
|
+
throw new Error(`Not supported: No Subtle Crypto support`);
|
|
295
|
+
|
|
296
|
+
let signature : ArrayBuffer;
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
signature = await this.subtleCrypto.sign(
|
|
300
|
+
importAlgorithm.operation,
|
|
301
|
+
key,
|
|
302
|
+
messageAsUint8Array
|
|
303
|
+
);
|
|
304
|
+
} catch (e) {
|
|
305
|
+
console.error(`JWT.sign(): Caught error while signing token:`);
|
|
306
|
+
console.error(e);
|
|
307
|
+
throw e;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// TODO Test
|
|
311
|
+
let signatureAsBase64 = Base64URL.stringify(new Uint8Array(signature));
|
|
312
|
+
let token = `${partialToken}.${signatureAsBase64}`;
|
|
313
|
+
|
|
314
|
+
return token;
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
private _decode(token : string): DecodedToken {
|
|
318
|
+
let parts = token.split('.');
|
|
319
|
+
if (parts.length !== 3)
|
|
320
|
+
throw new Error(`Invalid token '${token}': must have 3 parts separated by '.'`);
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
encodedHeader: parts[0],
|
|
324
|
+
encodedPayload: parts[1],
|
|
325
|
+
signature: parts[2],
|
|
326
|
+
|
|
327
|
+
header: JSON.parse(this._decodeBase64URL(parts[0])),
|
|
328
|
+
payload: JSON.parse(this._decodeBase64URL(parts[1])),
|
|
329
|
+
};
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
private _decodeBase64URL(string : string) {
|
|
333
|
+
string = string.replace(/-/g, '+').replace(/_/g, '/');
|
|
334
|
+
|
|
335
|
+
switch (string.length % 4) {
|
|
336
|
+
case 0:
|
|
337
|
+
break;
|
|
338
|
+
case 2:
|
|
339
|
+
string += '==';
|
|
340
|
+
break;
|
|
341
|
+
case 3:
|
|
342
|
+
string += '=';
|
|
343
|
+
break;
|
|
344
|
+
default:
|
|
345
|
+
throw new Error(`Illegal Base64URL string '${string}'`);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// TODO Use shim or document incompatible browsers
|
|
349
|
+
return decodeURIComponent(escape(atob(string)));
|
|
350
|
+
}
|
|
351
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function validateExpiry(exp : number, now : number, policy : 'ignore' | 'when-present' | 'force') {
|
|
2
|
+
|
|
3
|
+
// Define acceptable policies
|
|
4
|
+
|
|
5
|
+
const supportedPolicies = [
|
|
6
|
+
'when-present', 'force', 'ignore'
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
// Set defaults
|
|
10
|
+
|
|
11
|
+
policy = policy || 'when-present';
|
|
12
|
+
now = now || Date.now();
|
|
13
|
+
|
|
14
|
+
if (!supportedPolicies.includes(policy))
|
|
15
|
+
throw new Error(`Unsupported 'exp' validation strategy '${policy}'`);
|
|
16
|
+
|
|
17
|
+
if (policy !== 'ignore') {
|
|
18
|
+
if (typeof exp !== 'undefined') {
|
|
19
|
+
if (exp * 1000 < now)
|
|
20
|
+
throw new Error(`Token is expired`);
|
|
21
|
+
} else if (policy === 'force') {
|
|
22
|
+
throw new Error(`Non-expiring tokens are not acceptable`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface Options {
|
|
2
|
+
secretOrKey? : string;
|
|
3
|
+
algorithm? : string;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Assume the given UNIX clock time in milliseconds (as would be returned by Date.now()).
|
|
7
|
+
* When not specified, Date.now() is used to get the current time.
|
|
8
|
+
*/
|
|
9
|
+
now? : number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface EncodeOptions extends Options {
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface DecodeOptions extends Options {
|
|
16
|
+
validate?: ValidateOptions;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ValidateOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Whether to automatically verify the `exp` claim.
|
|
22
|
+
* When not specified, default is 'when-present'.
|
|
23
|
+
* Set `now` option to override the current time.
|
|
24
|
+
*/
|
|
25
|
+
exp? : 'when-present' | 'force' | 'ignore';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Token {
|
|
29
|
+
string : string;
|
|
30
|
+
claims : Record<string, any>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface DecodedToken {
|
|
34
|
+
encodedHeader : string;
|
|
35
|
+
encodedPayload : string;
|
|
36
|
+
signature : string;
|
|
37
|
+
|
|
38
|
+
header : Record<string,any>;
|
|
39
|
+
payload : Record<string,any>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
export interface JWTEngine {
|
|
44
|
+
encode(claims : Record<string,any>, options : EncodeOptions) : Promise<Token>;
|
|
45
|
+
validate(token : string, options : DecodeOptions) : Promise<Token>;
|
|
46
|
+
decodeUntrusted(token : string) : Promise<Token>;
|
|
47
|
+
}
|