@cfworker/jwt 4.0.5 → 5.0.0

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/README.md CHANGED
@@ -15,7 +15,7 @@ const jwt = request.headers.get('Authorization');
15
15
  const issuer = '...'; // Auth0 origin.
16
16
  const audience = '...'; // Auth0 client id.
17
17
 
18
- const result = await parseJwt(jwt, issuer, audience);
18
+ const result = await parseJwt({ jwt, issuer, audience });
19
19
  if (!result.valid) {
20
20
  console.log(result.reason); // Invalid issuer/audience, expired, etc
21
21
  } else {
package/dist/parse.d.ts CHANGED
@@ -1,2 +1,9 @@
1
1
  import { DecodedJwt, JwtParseResult } from './types.js';
2
- export declare function parseJwt(encodedToken: string, issuer: string, audience: string, resolveKey?: (decoded: DecodedJwt) => Promise<CryptoKey | null>): Promise<JwtParseResult>;
2
+ export interface JwtParseOptions {
3
+ jwt: string;
4
+ issuer: string | string[];
5
+ audience: string;
6
+ resolveKey?: (decoded: DecodedJwt) => Promise<CryptoKey | null>;
7
+ skewMs?: number;
8
+ }
9
+ export declare function parseJwt({ jwt, issuer, audience, resolveKey, skewMs }: JwtParseOptions): Promise<JwtParseResult>;
package/dist/parse.js CHANGED
@@ -2,11 +2,11 @@ import { algs, algToHash } from './algs.js';
2
2
  import { decodeJwt } from './decode.js';
3
3
  import { getKey } from './jwks.js';
4
4
  import { verifyJwtSignature } from './verify.js';
5
- const skewMs = 30 * 1000;
6
- export async function parseJwt(encodedToken, issuer, audience, resolveKey = getKey) {
5
+ const defaultSkewMs = 60 * 1000;
6
+ export async function parseJwt({ jwt, issuer, audience, resolveKey = getKey, skewMs = defaultSkewMs }) {
7
7
  let decoded;
8
8
  try {
9
- decoded = decodeJwt(encodedToken);
9
+ decoded = decodeJwt(jwt);
10
10
  }
11
11
  catch {
12
12
  return { valid: false, reason: `Unable to decode JWT.` };
@@ -55,10 +55,10 @@ export async function parseJwt(encodedToken, issuer, audience, resolveKey = getK
55
55
  reason: `Invalid JWT audience claim (aud) ${JSON.stringify(aud)}. Expected a string or a non-empty array of strings.`
56
56
  };
57
57
  }
58
- if (iss !== issuer) {
58
+ if (!(iss === issuer || (Array.isArray(issuer) && issuer.includes(iss)))) {
59
59
  return {
60
60
  valid: false,
61
- reason: `Invalid JWT issuer claim (iss) ${JSON.stringify(decoded.payload.iss)}. Expected "${issuer}".`
61
+ reason: `Invalid JWT issuer claim (iss) ${JSON.stringify(decoded.payload.iss)}. Expected ${JSON.stringify(issuer)}.`
62
62
  };
63
63
  }
64
64
  if (typeof exp !== 'number') {
@@ -137,6 +137,6 @@ export async function parseJwt(encodedToken, issuer, audience, resolveKey = getK
137
137
  if (!signatureValid) {
138
138
  return { valid: false, reason: `JWT signature is invalid.` };
139
139
  }
140
- const payload = decoded.payload;
141
- return { valid: true, payload };
140
+ const { header, payload } = decoded;
141
+ return { valid: true, header, payload };
142
142
  }
package/dist/types.d.ts CHANGED
@@ -29,6 +29,7 @@ export interface JsonWebKeyset {
29
29
  }
30
30
  export interface ValidJwtParseResult {
31
31
  valid: true;
32
+ header: JwtHeader;
32
33
  payload: JwtPayload;
33
34
  }
34
35
  export interface InvalidJwtParseResult {
@@ -61,4 +62,4 @@ export interface MtlsEndpointAliases {
61
62
  introspection_endpoint?: string;
62
63
  device_authorization_endpoint?: string;
63
64
  }
64
- export declare type JwtParseResult = ValidJwtParseResult | InvalidJwtParseResult;
65
+ export type JwtParseResult = ValidJwtParseResult | InvalidJwtParseResult;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cfworker/jwt",
3
- "version": "4.0.5",
3
+ "version": "5.0.0",
4
4
  "description": "Tiny lib for decoding JWTs and verifying signatures, using native crypto APIs",
5
5
  "keywords": [
6
6
  "jwt",
@@ -31,19 +31,19 @@
31
31
  "scripts": {
32
32
  "build": "tsc --build",
33
33
  "clean": "tsc --build --clean",
34
- "test": "cfworker test test/**/*.spec.ts --nocheck"
34
+ "pretest": "esbuild test/test.ts --target=esnext --bundle --format=esm --conditions=worker,browser --outdir=dist-test --ignore-annotations",
35
+ "test": "node ../../test.mjs"
35
36
  },
36
37
  "dependencies": {
37
- "@cfworker/worker-types": "^1.12.3",
38
- "@cloudflare/workers-types": "^2.2.2",
39
- "rfc4648": "^1.5.2"
38
+ "rfc4648": "^1.5.3"
40
39
  },
41
40
  "devDependencies": {
42
- "@cfworker/dev": "^1.14.2",
43
- "@types/chai": "^4.3.3",
44
- "@types/mocha": "^10.0.0",
45
- "chai": "^4.3.6",
46
- "mocha": "^10.0.0",
47
- "typescript": "^4.8.4"
41
+ "@types/chai": "^4.3.17",
42
+ "@types/mocha": "^10.0.7",
43
+ "chai": "^5.1.1",
44
+ "esbuild": "^0.23.1",
45
+ "mocha": "^10.7.3",
46
+ "typescript": "^5.5.4",
47
+ "wrangler": "^3.72.0"
48
48
  }
49
49
  }
@@ -0,0 +1,6 @@
1
+ interface JsonWebKey {
2
+ x5c?: string[];
3
+ kid?: string;
4
+ x5t?: string;
5
+ n?: string;
6
+ }
package/src/parse.ts CHANGED
@@ -4,20 +4,55 @@ import { getKey } from './jwks.js';
4
4
  import { DecodedJwt, JwtParseResult } from './types.js';
5
5
  import { verifyJwtSignature } from './verify.js';
6
6
 
7
- const skewMs = 30 * 1000;
7
+ const defaultSkewMs = 60 * 1000;
8
+
9
+ export interface JwtParseOptions {
10
+ /**
11
+ * The JWT to parse.
12
+ */
13
+ jwt: string;
14
+
15
+ /**
16
+ * Permitted issuer(s) of the JWT. Used to validate the iss claim.
17
+ * Note: if you're using the default resolveKey function, OIDC discovery will be used
18
+ * to fetch the public key(s) for the issuer.
19
+ */
20
+ issuer: string | string[];
21
+
22
+ /**
23
+ * Expected audience of the JWT.
24
+ */
25
+ audience: string;
26
+
27
+ /**
28
+ * Given a decoded (but not fully verified) JWT, resolve the public key that
29
+ * should be used to verify the signature. Typical implementations will use
30
+ * the "kid" claim to look up the key in a JWKS endpoint or other key store.
31
+ * If the key cannot be resolved, the function should return null.
32
+ * @param decoded The decoded (but not fully verified / unsafe) JWT.
33
+ */
34
+ resolveKey?: (decoded: DecodedJwt) => Promise<CryptoKey | null>;
35
+
36
+ /**
37
+ * The maximum skew in milliseconds to allow when validating iat, nbf, and exp claims.
38
+ * Defaults to 60 seconds.
39
+ */
40
+ skewMs?: number;
41
+ }
8
42
 
9
43
  /**
10
44
  * Parse a JWT.
11
45
  */
12
- export async function parseJwt(
13
- encodedToken: string,
14
- issuer: string,
15
- audience: string,
16
- resolveKey: (decoded: DecodedJwt) => Promise<CryptoKey | null> = getKey
17
- ): Promise<JwtParseResult> {
46
+ export async function parseJwt({
47
+ jwt,
48
+ issuer,
49
+ audience,
50
+ resolveKey = getKey,
51
+ skewMs = defaultSkewMs
52
+ }: JwtParseOptions): Promise<JwtParseResult> {
18
53
  let decoded: DecodedJwt;
19
54
  try {
20
- decoded = decodeJwt(encodedToken);
55
+ decoded = decodeJwt(jwt);
21
56
  } catch {
22
57
  return { valid: false, reason: `Unable to decode JWT.` };
23
58
  }
@@ -78,12 +113,12 @@ export async function parseJwt(
78
113
  };
79
114
  }
80
115
 
81
- if (iss !== issuer) {
116
+ if (!(iss === issuer || (Array.isArray(issuer) && issuer.includes(iss)))) {
82
117
  return {
83
118
  valid: false,
84
119
  reason: `Invalid JWT issuer claim (iss) ${JSON.stringify(
85
120
  decoded.payload.iss
86
- )}. Expected "${issuer}".`
121
+ )}. Expected ${JSON.stringify(issuer)}.`
87
122
  };
88
123
  }
89
124
 
@@ -172,6 +207,6 @@ export async function parseJwt(
172
207
  if (!signatureValid) {
173
208
  return { valid: false, reason: `JWT signature is invalid.` };
174
209
  }
175
- const payload = decoded.payload;
176
- return { valid: true, payload };
210
+ const { header, payload } = decoded;
211
+ return { valid: true, header, payload };
177
212
  }
package/src/types.ts CHANGED
@@ -41,6 +41,7 @@ export interface JsonWebKeyset {
41
41
 
42
42
  export interface ValidJwtParseResult {
43
43
  valid: true;
44
+ header: JwtHeader;
44
45
  payload: JwtPayload;
45
46
  }
46
47
 
package/tsconfig.json CHANGED
@@ -1,17 +1,11 @@
1
1
  {
2
2
  "extends": "../../tsconfig-base",
3
3
  "compilerOptions": {
4
- "target": "ES2021",
4
+ "target": "ESNext",
5
5
  "lib": ["ESNext", "WebWorker", "Webworker.Iterable"],
6
- "types": [
7
- "chai",
8
- "mocha",
9
- "@cfworker/worker-types",
10
- "@cloudflare/workers-types"
11
- ],
12
6
  "outDir": "dist",
13
7
  "rootDir": "./src"
14
8
  },
15
9
  "include": ["src"],
16
- "references": [{ "path": "../base64url" }]
10
+ "references": []
17
11
  }