@cfworker/jwt 7.0.4 → 7.0.5

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.
Files changed (67) hide show
  1. package/dist/commonjs/algs.d.ts +1 -0
  2. package/dist/commonjs/algs.d.ts.map +1 -0
  3. package/dist/commonjs/algs.js +1 -0
  4. package/dist/commonjs/algs.js.map +1 -0
  5. package/dist/commonjs/decode.d.ts +1 -0
  6. package/dist/commonjs/decode.d.ts.map +1 -0
  7. package/dist/commonjs/decode.js +11 -1
  8. package/dist/commonjs/decode.js.map +1 -0
  9. package/dist/commonjs/discovery.d.ts +1 -0
  10. package/dist/commonjs/discovery.d.ts.map +1 -0
  11. package/dist/commonjs/discovery.js +1 -0
  12. package/dist/commonjs/discovery.js.map +1 -0
  13. package/dist/commonjs/index.d.ts +1 -0
  14. package/dist/commonjs/index.d.ts.map +1 -0
  15. package/dist/commonjs/index.js +1 -0
  16. package/dist/commonjs/index.js.map +1 -0
  17. package/dist/commonjs/jwks.d.ts +1 -0
  18. package/dist/commonjs/jwks.d.ts.map +1 -0
  19. package/dist/commonjs/jwks.js +12 -5
  20. package/dist/commonjs/jwks.js.map +1 -0
  21. package/dist/commonjs/package.json +2 -1
  22. package/dist/commonjs/parse.d.ts +1 -0
  23. package/dist/commonjs/parse.d.ts.map +1 -0
  24. package/dist/commonjs/parse.js +1 -0
  25. package/dist/commonjs/parse.js.map +1 -0
  26. package/dist/commonjs/types.d.ts +1 -0
  27. package/dist/commonjs/types.d.ts.map +1 -0
  28. package/dist/commonjs/types.js +1 -0
  29. package/dist/commonjs/types.js.map +1 -0
  30. package/dist/commonjs/verify.d.ts +1 -0
  31. package/dist/commonjs/verify.d.ts.map +1 -0
  32. package/dist/commonjs/verify.js +10 -1
  33. package/dist/commonjs/verify.js.map +1 -0
  34. package/dist/esm/algs.d.ts +1 -0
  35. package/dist/esm/algs.d.ts.map +1 -0
  36. package/dist/esm/algs.js +1 -0
  37. package/dist/esm/algs.js.map +1 -0
  38. package/dist/esm/decode.d.ts +1 -0
  39. package/dist/esm/decode.d.ts.map +1 -0
  40. package/dist/esm/decode.js +11 -1
  41. package/dist/esm/decode.js.map +1 -0
  42. package/dist/esm/discovery.d.ts +1 -0
  43. package/dist/esm/discovery.d.ts.map +1 -0
  44. package/dist/esm/discovery.js +1 -0
  45. package/dist/esm/discovery.js.map +1 -0
  46. package/dist/esm/index.d.ts +1 -0
  47. package/dist/esm/index.d.ts.map +1 -0
  48. package/dist/esm/index.js +1 -0
  49. package/dist/esm/index.js.map +1 -0
  50. package/dist/esm/jwks.d.ts +1 -0
  51. package/dist/esm/jwks.d.ts.map +1 -0
  52. package/dist/esm/jwks.js +12 -5
  53. package/dist/esm/jwks.js.map +1 -0
  54. package/dist/esm/package.json +2 -1
  55. package/dist/esm/parse.d.ts +1 -0
  56. package/dist/esm/parse.d.ts.map +1 -0
  57. package/dist/esm/parse.js +1 -0
  58. package/dist/esm/parse.js.map +1 -0
  59. package/dist/esm/types.d.ts +1 -0
  60. package/dist/esm/types.d.ts.map +1 -0
  61. package/dist/esm/types.js +1 -0
  62. package/dist/esm/types.js.map +1 -0
  63. package/dist/esm/verify.d.ts +1 -0
  64. package/dist/esm/verify.d.ts.map +1 -0
  65. package/dist/esm/verify.js +10 -1
  66. package/dist/esm/verify.js.map +1 -0
  67. package/package.json +11 -9
@@ -1,2 +1,3 @@
1
1
  export declare const algToHash: Record<string, string>;
2
2
  export declare const algs: string[];
3
+ //# sourceMappingURL=algs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"algs.d.ts","sourceRoot":"","sources":["../../src/algs.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAI5C,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,MAAM,EAA2B,CAAC"}
@@ -7,3 +7,4 @@ exports.algToHash = {
7
7
  RS512: 'SHA-512'
8
8
  };
9
9
  exports.algs = Object.keys(exports.algToHash);
10
+ //# sourceMappingURL=algs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"algs.js","sourceRoot":"","sources":["../../src/algs.ts"],"names":[],"mappings":";;;AAAa,QAAA,SAAS,GAA2B;IAC/C,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,SAAS;CACjB,CAAC;AAEW,QAAA,IAAI,GAAa,MAAM,CAAC,IAAI,CAAC,QAAA,SAAS,CAAC,CAAC","sourcesContent":["export const algToHash: Record<string, string> = {\n RS256: 'SHA-256',\n RS384: 'SHA-384',\n RS512: 'SHA-512'\n};\n\nexport const algs: string[] = Object.keys(algToHash);\n"]}
@@ -1,2 +1,3 @@
1
1
  import { DecodedJwt } from './types.js';
2
2
  export declare function decodeJwt(token: string): DecodedJwt;
3
+ //# sourceMappingURL=decode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode.d.ts","sourceRoot":"","sources":["../../src/decode.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKxC,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAwBnD"}
@@ -3,7 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.decodeJwt = decodeJwt;
4
4
  const rfc4648_1 = require("rfc4648");
5
5
  function decodeJwt(token) {
6
- const [header, payload, signature] = token.split('.');
6
+ const segments = token.split('.');
7
+ const header = segments[0];
8
+ const payload = segments[1];
9
+ const signature = segments[2];
10
+ if (segments.length !== 3 ||
11
+ header === undefined ||
12
+ payload === undefined ||
13
+ signature === undefined) {
14
+ throw new TypeError('JWT must contain three segments.');
15
+ }
7
16
  const decoder = new TextDecoder();
8
17
  return {
9
18
  header: JSON.parse(decoder.decode(rfc4648_1.base64url.parse(header, { loose: true }))),
@@ -12,3 +21,4 @@ function decodeJwt(token) {
12
21
  raw: { header, payload, signature }
13
22
  };
14
23
  }
24
+ //# sourceMappingURL=decode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode.js","sourceRoot":"","sources":["../../src/decode.ts"],"names":[],"mappings":";;;AACA,qCAAoC;AAMpC,mBAA0B,KAAa;IACrC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9B,IACE,QAAQ,CAAC,MAAM,KAAK,CAAC;QACrB,MAAM,KAAK,SAAS;QACpB,OAAO,KAAK,SAAS;QACrB,SAAS,KAAK,SAAS,EACvB,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,KAAK,CAChB,OAAO,CAAC,MAAM,CAAC,mBAAS,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CACzD;QACD,OAAO,EAAE,IAAI,CAAC,KAAK,CACjB,OAAO,CAAC,MAAM,CAAC,mBAAS,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAC1D;QACD,SAAS,EAAE,mBAAS,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACtD,GAAG,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE;KACpC,CAAC;AACJ,CAAC","sourcesContent":["// @ts-ignore\nimport { base64url } from 'rfc4648';\nimport { DecodedJwt } from './types.js';\n\n/**\n * Decode a JWT into header, payload, and signature components.\n */\nexport function decodeJwt(token: string): DecodedJwt {\n const segments = token.split('.');\n const header = segments[0];\n const payload = segments[1];\n const signature = segments[2];\n if (\n segments.length !== 3 ||\n header === undefined ||\n payload === undefined ||\n signature === undefined\n ) {\n throw new TypeError('JWT must contain three segments.');\n }\n const decoder = new TextDecoder();\n return {\n header: JSON.parse(\n decoder.decode(base64url.parse(header, { loose: true }))\n ),\n payload: JSON.parse(\n decoder.decode(base64url.parse(payload, { loose: true }))\n ),\n signature: base64url.parse(signature, { loose: true }),\n raw: { header, payload, signature }\n };\n}\n"]}
@@ -1,2 +1,3 @@
1
1
  import type { IssuerMetadata } from './types.js';
2
2
  export declare function getIssuerMetadata(issuer: string): Promise<IssuerMetadata>;
3
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,CAAC,CAazB"}
@@ -13,3 +13,4 @@ async function getIssuerMetadata(issuer) {
13
13
  }
14
14
  return response.json();
15
15
  }
16
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/discovery.ts"],"names":[],"mappings":";;;AAKO,KAAK,4BACV,MAAc;IAEd,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAChC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC;IACtB,CAAC;IACD,GAAG,CAAC,QAAQ,IAAI,kCAAkC,CAAC;IACnD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,8CAA8C,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CACpG,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC","sourcesContent":["import type { IssuerMetadata } from './types.js';\n\n/**\n * Fetch an oidc discovery document\n */\nexport async function getIssuerMetadata(\n issuer: string\n): Promise<IssuerMetadata> {\n const url = new URL(issuer);\n if (!url.pathname.endsWith('/')) {\n url.pathname += '/';\n }\n url.pathname += '.well-known/openid-configuration';\n const response = await fetch(url.href);\n if (!response.ok) {\n throw new Error(\n `Error loading OpenID discovery document at ${url.href}. ${response.status} ${response.statusText}`\n );\n }\n return response.json();\n}\n"]}
@@ -3,3 +3,4 @@ export { getJwks, getKey, importKey } from './jwks.js';
3
3
  export { parseJwt } from './parse.js';
4
4
  export * from './types.js';
5
5
  export { verifyJwtSignature } from './verify.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
@@ -26,3 +26,4 @@ Object.defineProperty(exports, "parseJwt", { enumerable: true, get: function ()
26
26
  __exportStar(require("./types.js"), exports);
27
27
  var verify_js_1 = require("./verify.js");
28
28
  Object.defineProperty(exports, "verifyJwtSignature", { enumerable: true, get: function () { return verify_js_1.verifyJwtSignature; } });
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAClB,qCAAuD;AAA9C,kGAAA,OAAO,OAAA;AAAE,iGAAA,MAAM,OAAA;AAAE,oGAAA,SAAS,OAAA;AACnC,uCAAsC;AAA7B,oGAAA,QAAQ,OAAA;AACjB,6CAA2B;AAC3B,yCAAiD;AAAxC,+GAAA,kBAAkB,OAAA","sourcesContent":["export { decodeJwt } from './decode.js';\nexport { getJwks, getKey, importKey } from './jwks.js';\nexport { parseJwt } from './parse.js';\nexport * from './types.js';\nexport { verifyJwtSignature } from './verify.js';\n"]}
@@ -2,3 +2,4 @@ import { DecodedJwt, JsonWebKeyset } from './types.js';
2
2
  export declare function getJwks(issuer: string): Promise<JsonWebKeyset>;
3
3
  export declare function importKey(iss: string, jwk: JsonWebKey): Promise<void>;
4
4
  export declare function getKey(decoded: DecodedJwt): Promise<CryptoKey>;
5
+ //# sourceMappingURL=jwks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwks.d.ts","sourceRoot":"","sources":["../../src/jwks.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAKvD,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqBpE;AASD,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC3E;AAKD,wBAAsB,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAoBpE"}
@@ -24,7 +24,7 @@ async function getJwks(issuer) {
24
24
  }
25
25
  return response.json();
26
26
  }
27
- const importedKeys = {};
27
+ const importedKeys = new Map();
28
28
  async function importKey(iss, jwk) {
29
29
  if (jwk.kty !== 'RSA') {
30
30
  throw new Error(`Unsupported jwk key type (kty) "${jwk.kty}": Full JWK was ${JSON.stringify(jwk)}`);
@@ -34,18 +34,25 @@ async function importKey(iss, jwk) {
34
34
  throw new Error(`Unsupported jwk Algorithm (alg) "${jwk.alg}": Full JWK was ${JSON.stringify(jwk)}`);
35
35
  }
36
36
  const key = await crypto.subtle.importKey('jwk', jwk, { name: 'RSASSA-PKCS1-v1_5', hash }, false, ['verify']);
37
- importedKeys[iss] = importedKeys[iss] || {};
38
- importedKeys[iss][jwk.kid ?? 'default'] = key;
37
+ let issuerKeys = importedKeys.get(iss);
38
+ if (!issuerKeys) {
39
+ issuerKeys = new Map();
40
+ importedKeys.set(iss, issuerKeys);
41
+ }
42
+ issuerKeys.set(jwk.kid ?? 'default', key);
39
43
  }
40
44
  async function getKey(decoded) {
41
45
  const { header: { kid = 'default' }, payload: { iss } } = decoded;
42
- if (!importedKeys[iss]) {
46
+ let issuerKeys = importedKeys.get(iss);
47
+ if (!issuerKeys) {
43
48
  const jwks = await getJwks(iss);
44
49
  await Promise.all(jwks.keys.map(jwk => importKey(iss, jwk)));
50
+ issuerKeys = importedKeys.get(iss);
45
51
  }
46
- const key = importedKeys[iss][kid];
52
+ const key = issuerKeys?.get(kid);
47
53
  if (!key) {
48
54
  throw new Error(`Error jwk not found. iss: ${iss}; kid: ${kid};`);
49
55
  }
50
56
  return key;
51
57
  }
58
+ //# sourceMappingURL=jwks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwks.js","sourceRoot":"","sources":["../../src/jwks.ts"],"names":[],"mappings":"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","sourcesContent":["import { algToHash } from './algs.js';\nimport { getIssuerMetadata } from './discovery.js';\nimport { DecodedJwt, JsonWebKeyset } from './types.js';\n\n/**\n * Fetch a json web keyset.\n */\nexport async function getJwks(issuer: string): Promise<JsonWebKeyset> {\n const issuerMetadata = await getIssuerMetadata(issuer);\n\n let url;\n if (issuerMetadata.jwks_uri) {\n url = new URL(issuerMetadata.jwks_uri);\n } else {\n url = new URL(issuer);\n if (!url.pathname.endsWith('/')) {\n url.pathname += '/';\n }\n url.pathname += '.well-known/jwks.json';\n }\n\n const response = await fetch(url.href);\n if (!response.ok) {\n throw new Error(\n `Error loading jwks at ${url.href}. ${response.status} ${response.statusText}`\n );\n }\n return response.json();\n}\n\nconst importedKeys = new Map<string, Map<string, CryptoKey>>();\n\n/**\n * Import and cache a JsonWebKeyset\n * @param iss The issuer. Serves as the first-level cache key.\n * @param jwks The JsonWebKeyset to import.\n */\nexport async function importKey(iss: string, jwk: JsonWebKey): Promise<void> {\n if (jwk.kty !== 'RSA') {\n throw new Error(\n `Unsupported jwk key type (kty) \"${\n jwk.kty\n }\": Full JWK was ${JSON.stringify(jwk)}`\n );\n }\n // alg is not mandatory in a JWK but is available in the JWT, for now we default to\n // SHA-256 (RS256) because this is the most common but evaluating the key length\n // of the JWKS is probably an ideal way of identifying what the alg is.\n const hash = jwk.alg ? algToHash[jwk.alg] : 'SHA-256';\n if (!hash) {\n throw new Error(\n `Unsupported jwk Algorithm (alg) \"${\n jwk.alg\n }\": Full JWK was ${JSON.stringify(jwk)}`\n );\n }\n const key = await crypto.subtle.importKey(\n 'jwk',\n jwk,\n { name: 'RSASSA-PKCS1-v1_5', hash },\n false,\n ['verify']\n );\n let issuerKeys = importedKeys.get(iss);\n if (!issuerKeys) {\n issuerKeys = new Map();\n importedKeys.set(iss, issuerKeys);\n }\n issuerKeys.set(jwk.kid ?? 'default', key);\n}\n\n/**\n * Get the CryptoKey associated with the JWT's issuer.\n */\nexport async function getKey(decoded: DecodedJwt): Promise<CryptoKey> {\n const {\n header: { kid = 'default' },\n payload: { iss }\n } = decoded;\n\n let issuerKeys = importedKeys.get(iss);\n if (!issuerKeys) {\n const jwks = await getJwks(iss);\n await Promise.all(jwks.keys.map(jwk => importKey(iss, jwk)));\n issuerKeys = importedKeys.get(iss);\n }\n\n const key = issuerKeys?.get(kid);\n\n if (!key) {\n throw new Error(`Error jwk not found. iss: ${iss}; kid: ${kid};`);\n }\n\n return key;\n}\n"]}
@@ -1,3 +1,4 @@
1
1
  {
2
- "type": "commonjs"
2
+ "type": "commonjs",
3
+ "sideEffects": false
3
4
  }
@@ -7,3 +7,4 @@ export interface JwtParseOptions {
7
7
  skewMs?: number;
8
8
  }
9
9
  export declare function parseJwt({ jwt, issuer, audience, resolveKey, skewMs }: JwtParseOptions): Promise<JwtParseResult>;
10
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/parse.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAwB,cAAc,EAAE,MAAM,YAAY,CAAC;AAK9E,MAAM,WAAW,eAAe;IAI9B,GAAG,EAAE,MAAM,CAAC;IAOZ,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAK1B,QAAQ,EAAE,MAAM,CAAC;IASjB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAMhE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,wBAAsB,QAAQ,CAAC,EAC7B,GAAG,EACH,MAAM,EACN,QAAQ,EACR,UAAmB,EACnB,MAAsB,EACvB,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CA4M3C"}
@@ -188,3 +188,4 @@ async function parseJwt({ jwt, issuer, audience, resolveKey = jwks_js_1.getKey,
188
188
  const { header, payload } = decoded;
189
189
  return { valid: true, header, payload };
190
190
  }
191
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/parse.ts"],"names":[],"mappings":"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","sourcesContent":["import { algs, algToHash } from './algs.js';\nimport { decodeJwt } from './decode.js';\nimport { getKey } from './jwks.js';\nimport { DecodedJwt, InvalidJwtReasonCode, JwtParseResult } from './types.js';\nimport { verifyJwtSignature } from './verify.js';\n\nconst defaultSkewMs = 60 * 1000;\n\nexport interface JwtParseOptions {\n /**\n * The JWT to parse.\n */\n jwt: string;\n\n /**\n * Permitted issuer(s) of the JWT. Used to validate the iss claim.\n * Note: if you're using the default resolveKey function, OIDC discovery will be used\n * to fetch the public key(s) for the issuer.\n */\n issuer: string | string[];\n\n /**\n * Expected audience of the JWT.\n */\n audience: string;\n\n /**\n * Given a decoded (but not fully verified) JWT, resolve the public key that\n * should be used to verify the signature. Typical implementations will use\n * the \"kid\" claim to look up the key in a JWKS endpoint or other key store.\n * If the key cannot be resolved, the function should return null.\n * @param decoded The decoded (but not fully verified / unsafe) JWT.\n */\n resolveKey?: (decoded: DecodedJwt) => Promise<CryptoKey | null>;\n\n /**\n * The maximum skew in milliseconds to allow when validating iat, nbf, and exp claims.\n * Defaults to 60 seconds.\n */\n skewMs?: number;\n}\n\n/**\n * Parse a JWT.\n */\nexport async function parseJwt({\n jwt,\n issuer,\n audience,\n resolveKey = getKey,\n skewMs = defaultSkewMs\n}: JwtParseOptions): Promise<JwtParseResult> {\n let decoded: DecodedJwt;\n try {\n decoded = decodeJwt(jwt);\n } catch {\n return {\n valid: false,\n reason: `Unable to decode JWT.`,\n reasonCode: InvalidJwtReasonCode.Other\n };\n }\n const { typ, alg } = decoded.header;\n if (typeof typ !== 'undefined' && typ !== 'JWT') {\n return {\n valid: false,\n reason: `Invalid JWT type ${JSON.stringify(typ)}. Expected \"JWT\".`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n if (!algToHash[alg]) {\n return {\n valid: false,\n reason: `Invalid JWT algorithm ${JSON.stringify(\n alg\n )}. Supported: ${algs}.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n\n const { sub, aud, iss, iat, exp, nbf } = decoded.payload;\n if (typeof sub !== 'string') {\n return {\n valid: false,\n reason: `Subject claim (sub) is required and must be a string. Received ${JSON.stringify(\n sub\n )}.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n\n if (typeof aud === 'string') {\n if (aud !== audience) {\n return {\n valid: false,\n reason: `Invalid JWT audience claim (aud) ${JSON.stringify(\n aud\n )}. Expected \"${audience}\".`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n } else if (\n Array.isArray(aud) &&\n aud.length > 0 &&\n aud.every(a => typeof a === 'string')\n ) {\n if (!aud.includes(audience)) {\n return {\n valid: false,\n reason: `Invalid JWT audience claim array (aud) ${JSON.stringify(\n aud\n )}. Does not include \"${audience}\".`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n } else {\n return {\n valid: false,\n reason: `Invalid JWT audience claim (aud) ${JSON.stringify(\n aud\n )}. Expected a string or a non-empty array of strings.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n\n if (!(iss === issuer || (Array.isArray(issuer) && issuer.includes(iss)))) {\n return {\n valid: false,\n reason: `Invalid JWT issuer claim (iss) ${JSON.stringify(\n decoded.payload.iss\n )}. Expected ${JSON.stringify(issuer)}.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n\n if (typeof exp !== 'number') {\n return {\n valid: false,\n reason: `Invalid JWT expiry date claim (exp) ${JSON.stringify(\n exp\n )}. Expected number.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n const currentDate = new Date(Date.now());\n const expiryDate = new Date(0);\n expiryDate.setUTCSeconds(exp);\n const expired = expiryDate.getTime() <= currentDate.getTime() - skewMs;\n if (expired) {\n return {\n valid: false,\n reason: `JWT is expired. Expiry date: ${expiryDate}; Current date: ${currentDate};`,\n reasonCode: InvalidJwtReasonCode.Expired,\n decoded\n };\n }\n\n if (nbf !== undefined) {\n if (typeof nbf !== 'number') {\n return {\n valid: false,\n reason: `Invalid JWT not before date claim (nbf) ${JSON.stringify(\n nbf\n )}. Expected number.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n const notBeforeDate = new Date(0);\n notBeforeDate.setUTCSeconds(nbf);\n const early = notBeforeDate.getTime() > currentDate.getTime() + skewMs;\n if (early) {\n return {\n valid: false,\n reason: `JWT cannot be used prior to not before date claim (nbf). Not before date: ${notBeforeDate}; Current date: ${currentDate};`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n }\n\n if (iat !== undefined) {\n if (typeof iat !== 'number') {\n return {\n valid: false,\n reason: `Invalid JWT issued at date claim (iat) ${JSON.stringify(\n iat\n )}. Expected number.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n const issuedAtDate = new Date(0);\n issuedAtDate.setUTCSeconds(iat);\n const postIssued = issuedAtDate.getTime() > currentDate.getTime() + skewMs;\n if (postIssued) {\n return {\n valid: false,\n reason: `JWT issued at date claim (iat) is in the future. Issued at date: ${issuedAtDate}; Current date: ${currentDate};`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n }\n\n let key: CryptoKey | null;\n try {\n key = await resolveKey(decoded);\n } catch (e) {\n return {\n valid: false,\n reason: `Error retrieving public key to verify JWT signature: ${\n e instanceof Error ? e.message : e\n }`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n if (!key) {\n return {\n valid: false,\n reason: `Unable to resolve public key to verify JWT signature.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n let signatureValid: boolean;\n try {\n signatureValid = await verifyJwtSignature(decoded, key);\n } catch {\n return {\n valid: false,\n reason: `Error verifying JWT signature.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n if (!signatureValid) {\n return {\n valid: false,\n reason: `JWT signature is invalid.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n const { header, payload } = decoded;\n return { valid: true, header, payload };\n}\n"]}
@@ -69,3 +69,4 @@ export interface MtlsEndpointAliases {
69
69
  device_authorization_endpoint?: string;
70
70
  }
71
71
  export type JwtParseResult = ValidJwtParseResult | InvalidJwtParseResult;
72
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AASD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,UAAU,CAAC;IACpB,SAAS,EAAE,UAAU,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,oBAAoB,CAAC;IACjC,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAED,oBAAY,oBAAoB;IAC9B,KAAK,IAAI;IACT,OAAO,IAAI;CACZ;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qCAAqC,CAAC,EAAE,MAAM,EAAE,CAAC;IACjD,gDAAgD,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5D,6CAA6C,CAAC,EAAE,MAAM,EAAE,CAAC;IACzD,wDAAwD,CAAC,EAAE,MAAM,EAAE,CAAC;IACpE,0CAA0C,CAAC,EAAE,MAAM,EAAE,CAAC;IACtD,qDAAqD,CAAC,EAAE,MAAM,EAAE,CAAC;IACjE,2CAA2C,CAAC,EAAE,MAAM,EAAE,CAAC;IACvD,qBAAqB,CAAC,EAAE,mBAAmB,CAAC;IAC5C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,CAAC;CACxC;AAED,MAAM,MAAM,cAAc,GAAG,mBAAmB,GAAG,qBAAqB,CAAC"}
@@ -6,3 +6,4 @@ var InvalidJwtReasonCode;
6
6
  InvalidJwtReasonCode[InvalidJwtReasonCode["Other"] = 0] = "Other";
7
7
  InvalidJwtReasonCode[InvalidJwtReasonCode["Expired"] = 1] = "Expired";
8
8
  })(InvalidJwtReasonCode || (exports.InvalidJwtReasonCode = InvalidJwtReasonCode = {}));
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";;;AAsDA,IAAY,oBAGX;AAHD,WAAY,oBAAoB;IAC9B,iEAAS,CAAA;IACT,qEAAW,CAAA;AACb,CAAC,EAHW,oBAAoB,aAApB,oBAAoB,GAApB,oBAAoB,QAG/B","sourcesContent":["export interface JwtPayload {\n iss: string;\n sub: string;\n aud: string | Array<string>;\n iat: number;\n exp: number;\n nbf?: number;\n jti?: string;\n}\n\nexport interface JwtHeader {\n typ?: string;\n alg: string;\n kid: string;\n jku?: string;\n}\n\nexport interface RawJwt {\n header: string;\n payload: string;\n signature: string;\n}\n\n/**\n * @typedef {object} DecodedJwt\n * @property {JwtHeader} header\n * @property {JwtPayload} payload\n * @property {string} signature\n * @property {RawJwt} raw\n */\nexport interface DecodedJwt {\n header: JwtHeader;\n payload: JwtPayload;\n signature: Uint8Array;\n raw: RawJwt;\n}\n\nexport interface JsonWebKeyset {\n keys: JsonWebKey[];\n}\n\nexport interface ValidJwtParseResult {\n valid: true;\n header: JwtHeader;\n payload: JwtPayload;\n}\n\nexport interface InvalidJwtParseResult {\n valid: false;\n reason: string;\n reasonCode: InvalidJwtReasonCode;\n decoded?: DecodedJwt;\n}\n\nexport enum InvalidJwtReasonCode {\n Other = 0,\n Expired = 1\n}\n\nexport interface IssuerMetadata {\n issuer: string;\n authorization_endpoint?: string;\n token_endpoint?: string;\n jwks_uri?: string;\n userinfo_endpoint?: string;\n revocation_endpoint?: string;\n end_session_endpoint?: string;\n registration_endpoint?: string;\n token_endpoint_auth_methods_supported?: string[];\n token_endpoint_auth_signing_alg_values_supported?: string[];\n introspection_endpoint_auth_methods_supported?: string[];\n introspection_endpoint_auth_signing_alg_values_supported?: string[];\n revocation_endpoint_auth_methods_supported?: string[];\n revocation_endpoint_auth_signing_alg_values_supported?: string[];\n request_object_signing_alg_values_supported?: string[];\n mtls_endpoint_aliases?: MtlsEndpointAliases;\n [key: string]: unknown;\n}\n\nexport interface MtlsEndpointAliases {\n token_endpoint?: string;\n userinfo_endpoint?: string;\n revocation_endpoint?: string;\n introspection_endpoint?: string;\n device_authorization_endpoint?: string;\n}\n\nexport type JwtParseResult = ValidJwtParseResult | InvalidJwtParseResult;\n"]}
@@ -1,2 +1,3 @@
1
1
  import { DecodedJwt } from './types.js';
2
2
  export declare function verifyJwtSignature(decoded: DecodedJwt, key: CryptoKey): Promise<boolean>;
3
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMxC,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,SAAS,GACb,OAAO,CAAC,OAAO,CAAC,CAqBlB"}
@@ -1,8 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.verifyJwtSignature = verifyJwtSignature;
4
+ const algs_js_1 = require("./algs.js");
4
5
  async function verifyJwtSignature(decoded, key) {
6
+ if (key.algorithm.name !== 'RSASSA-PKCS1-v1_5') {
7
+ throw new Error(`Unsupported key algorithm "${key.algorithm.name}": only RSASSA-PKCS1-v1_5 is supported.`);
8
+ }
9
+ const alg = decoded.header.alg;
10
+ if (!algs_js_1.algToHash[alg]) {
11
+ throw new Error(`Unsupported JWT algorithm "${alg}": must be one of ${Object.keys(algs_js_1.algToHash).join(', ')}.`);
12
+ }
5
13
  const encoder = new TextEncoder();
6
14
  const data = encoder.encode(`${decoded.raw.header}.${decoded.raw.payload}`);
7
- return crypto.subtle.verify('RSASSA-PKCS1-v1_5', key, decoded.signature, data);
15
+ return crypto.subtle.verify('RSASSA-PKCS1-v1_5', key, Uint8Array.from(decoded.signature), data);
8
16
  }
17
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":";;;AAAA,uCAAsC;AAO/B,KAAK,6BACV,OAAmB,EACnB,GAAc;IAEd,IAAI,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CACb,8BAA8B,GAAG,CAAC,SAAS,CAAC,IAAI,yCAAyC,CAC1F,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;IAC/B,IAAI,CAAC,mBAAS,CAAC,GAAG,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,8BAA8B,GAAG,qBAAqB,MAAM,CAAC,IAAI,CAAC,mBAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC3F,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAE5E,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CACzB,mBAAmB,EACnB,GAAG,EACH,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAClC,IAAI,CACL,CAAC;AACJ,CAAC","sourcesContent":["import { algToHash } from './algs.js';\nimport { DecodedJwt } from './types.js';\n\n/**\n * Verify the JWT's signature.\n * @param {DecodedJwt} decoded\n */\nexport async function verifyJwtSignature(\n decoded: DecodedJwt,\n key: CryptoKey\n): Promise<boolean> {\n if (key.algorithm.name !== 'RSASSA-PKCS1-v1_5') {\n throw new Error(\n `Unsupported key algorithm \"${key.algorithm.name}\": only RSASSA-PKCS1-v1_5 is supported.`\n );\n }\n const alg = decoded.header.alg;\n if (!algToHash[alg]) {\n throw new Error(\n `Unsupported JWT algorithm \"${alg}\": must be one of ${Object.keys(algToHash).join(', ')}.`\n );\n }\n const encoder = new TextEncoder();\n const data = encoder.encode(`${decoded.raw.header}.${decoded.raw.payload}`);\n\n return crypto.subtle.verify(\n 'RSASSA-PKCS1-v1_5',\n key,\n Uint8Array.from(decoded.signature),\n data\n );\n}\n"]}
@@ -1,2 +1,3 @@
1
1
  export declare const algToHash: Record<string, string>;
2
2
  export declare const algs: string[];
3
+ //# sourceMappingURL=algs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"algs.d.ts","sourceRoot":"","sources":["../../src/algs.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAI5C,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,MAAM,EAA2B,CAAC"}
package/dist/esm/algs.js CHANGED
@@ -4,3 +4,4 @@ export const algToHash = {
4
4
  RS512: 'SHA-512'
5
5
  };
6
6
  export const algs = Object.keys(algToHash);
7
+ //# sourceMappingURL=algs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"algs.js","sourceRoot":"","sources":["../../src/algs.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAA2B;IAC/C,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,SAAS;CACjB,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAa,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC","sourcesContent":["export const algToHash: Record<string, string> = {\n RS256: 'SHA-256',\n RS384: 'SHA-384',\n RS512: 'SHA-512'\n};\n\nexport const algs: string[] = Object.keys(algToHash);\n"]}
@@ -1,2 +1,3 @@
1
1
  import { DecodedJwt } from './types.js';
2
2
  export declare function decodeJwt(token: string): DecodedJwt;
3
+ //# sourceMappingURL=decode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode.d.ts","sourceRoot":"","sources":["../../src/decode.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAKxC,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAwBnD"}
@@ -1,6 +1,15 @@
1
1
  import { base64url } from 'rfc4648';
2
2
  export function decodeJwt(token) {
3
- const [header, payload, signature] = token.split('.');
3
+ const segments = token.split('.');
4
+ const header = segments[0];
5
+ const payload = segments[1];
6
+ const signature = segments[2];
7
+ if (segments.length !== 3 ||
8
+ header === undefined ||
9
+ payload === undefined ||
10
+ signature === undefined) {
11
+ throw new TypeError('JWT must contain three segments.');
12
+ }
4
13
  const decoder = new TextDecoder();
5
14
  return {
6
15
  header: JSON.parse(decoder.decode(base64url.parse(header, { loose: true }))),
@@ -9,3 +18,4 @@ export function decodeJwt(token) {
9
18
  raw: { header, payload, signature }
10
19
  };
11
20
  }
21
+ //# sourceMappingURL=decode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decode.js","sourceRoot":"","sources":["../../src/decode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAMpC,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC3B,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9B,IACE,QAAQ,CAAC,MAAM,KAAK,CAAC;QACrB,MAAM,KAAK,SAAS;QACpB,OAAO,KAAK,SAAS;QACrB,SAAS,KAAK,SAAS,EACvB,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,KAAK,CAChB,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CACzD;QACD,OAAO,EAAE,IAAI,CAAC,KAAK,CACjB,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAC1D;QACD,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACtD,GAAG,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE;KACpC,CAAC;AACJ,CAAC","sourcesContent":["// @ts-ignore\nimport { base64url } from 'rfc4648';\nimport { DecodedJwt } from './types.js';\n\n/**\n * Decode a JWT into header, payload, and signature components.\n */\nexport function decodeJwt(token: string): DecodedJwt {\n const segments = token.split('.');\n const header = segments[0];\n const payload = segments[1];\n const signature = segments[2];\n if (\n segments.length !== 3 ||\n header === undefined ||\n payload === undefined ||\n signature === undefined\n ) {\n throw new TypeError('JWT must contain three segments.');\n }\n const decoder = new TextDecoder();\n return {\n header: JSON.parse(\n decoder.decode(base64url.parse(header, { loose: true }))\n ),\n payload: JSON.parse(\n decoder.decode(base64url.parse(payload, { loose: true }))\n ),\n signature: base64url.parse(signature, { loose: true }),\n raw: { header, payload, signature }\n };\n}\n"]}
@@ -1,2 +1,3 @@
1
1
  import type { IssuerMetadata } from './types.js';
2
2
  export declare function getIssuerMetadata(issuer: string): Promise<IssuerMetadata>;
3
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,cAAc,CAAC,CAazB"}
@@ -10,3 +10,4 @@ export async function getIssuerMetadata(issuer) {
10
10
  }
11
11
  return response.json();
12
12
  }
13
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/discovery.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAc;IAEd,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAChC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC;IACtB,CAAC;IACD,GAAG,CAAC,QAAQ,IAAI,kCAAkC,CAAC;IACnD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,8CAA8C,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CACpG,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC","sourcesContent":["import type { IssuerMetadata } from './types.js';\n\n/**\n * Fetch an oidc discovery document\n */\nexport async function getIssuerMetadata(\n issuer: string\n): Promise<IssuerMetadata> {\n const url = new URL(issuer);\n if (!url.pathname.endsWith('/')) {\n url.pathname += '/';\n }\n url.pathname += '.well-known/openid-configuration';\n const response = await fetch(url.href);\n if (!response.ok) {\n throw new Error(\n `Error loading OpenID discovery document at ${url.href}. ${response.status} ${response.statusText}`\n );\n }\n return response.json();\n}\n"]}
@@ -3,3 +3,4 @@ export { getJwks, getKey, importKey } from './jwks.js';
3
3
  export { parseJwt } from './parse.js';
4
4
  export * from './types.js';
5
5
  export { verifyJwtSignature } from './verify.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
package/dist/esm/index.js CHANGED
@@ -3,3 +3,4 @@ export { getJwks, getKey, importKey } from './jwks.js';
3
3
  export { parseJwt } from './parse.js';
4
4
  export * from './types.js';
5
5
  export { verifyJwtSignature } from './verify.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC","sourcesContent":["export { decodeJwt } from './decode.js';\nexport { getJwks, getKey, importKey } from './jwks.js';\nexport { parseJwt } from './parse.js';\nexport * from './types.js';\nexport { verifyJwtSignature } from './verify.js';\n"]}
@@ -2,3 +2,4 @@ import { DecodedJwt, JsonWebKeyset } from './types.js';
2
2
  export declare function getJwks(issuer: string): Promise<JsonWebKeyset>;
3
3
  export declare function importKey(iss: string, jwk: JsonWebKey): Promise<void>;
4
4
  export declare function getKey(decoded: DecodedJwt): Promise<CryptoKey>;
5
+ //# sourceMappingURL=jwks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwks.d.ts","sourceRoot":"","sources":["../../src/jwks.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAKvD,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAqBpE;AASD,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC3E;AAKD,wBAAsB,MAAM,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAoBpE"}
package/dist/esm/jwks.js CHANGED
@@ -19,7 +19,7 @@ export async function getJwks(issuer) {
19
19
  }
20
20
  return response.json();
21
21
  }
22
- const importedKeys = {};
22
+ const importedKeys = new Map();
23
23
  export async function importKey(iss, jwk) {
24
24
  if (jwk.kty !== 'RSA') {
25
25
  throw new Error(`Unsupported jwk key type (kty) "${jwk.kty}": Full JWK was ${JSON.stringify(jwk)}`);
@@ -29,18 +29,25 @@ export async function importKey(iss, jwk) {
29
29
  throw new Error(`Unsupported jwk Algorithm (alg) "${jwk.alg}": Full JWK was ${JSON.stringify(jwk)}`);
30
30
  }
31
31
  const key = await crypto.subtle.importKey('jwk', jwk, { name: 'RSASSA-PKCS1-v1_5', hash }, false, ['verify']);
32
- importedKeys[iss] = importedKeys[iss] || {};
33
- importedKeys[iss][jwk.kid ?? 'default'] = key;
32
+ let issuerKeys = importedKeys.get(iss);
33
+ if (!issuerKeys) {
34
+ issuerKeys = new Map();
35
+ importedKeys.set(iss, issuerKeys);
36
+ }
37
+ issuerKeys.set(jwk.kid ?? 'default', key);
34
38
  }
35
39
  export async function getKey(decoded) {
36
40
  const { header: { kid = 'default' }, payload: { iss } } = decoded;
37
- if (!importedKeys[iss]) {
41
+ let issuerKeys = importedKeys.get(iss);
42
+ if (!issuerKeys) {
38
43
  const jwks = await getJwks(iss);
39
44
  await Promise.all(jwks.keys.map(jwk => importKey(iss, jwk)));
45
+ issuerKeys = importedKeys.get(iss);
40
46
  }
41
- const key = importedKeys[iss][kid];
47
+ const key = issuerKeys?.get(kid);
42
48
  if (!key) {
43
49
  throw new Error(`Error jwk not found. iss: ${iss}; kid: ${kid};`);
44
50
  }
45
51
  return key;
46
52
  }
53
+ //# sourceMappingURL=jwks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwks.js","sourceRoot":"","sources":["../../src/jwks.ts"],"names":[],"mappings":"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","sourcesContent":["import { algToHash } from './algs.js';\nimport { getIssuerMetadata } from './discovery.js';\nimport { DecodedJwt, JsonWebKeyset } from './types.js';\n\n/**\n * Fetch a json web keyset.\n */\nexport async function getJwks(issuer: string): Promise<JsonWebKeyset> {\n const issuerMetadata = await getIssuerMetadata(issuer);\n\n let url;\n if (issuerMetadata.jwks_uri) {\n url = new URL(issuerMetadata.jwks_uri);\n } else {\n url = new URL(issuer);\n if (!url.pathname.endsWith('/')) {\n url.pathname += '/';\n }\n url.pathname += '.well-known/jwks.json';\n }\n\n const response = await fetch(url.href);\n if (!response.ok) {\n throw new Error(\n `Error loading jwks at ${url.href}. ${response.status} ${response.statusText}`\n );\n }\n return response.json();\n}\n\nconst importedKeys = new Map<string, Map<string, CryptoKey>>();\n\n/**\n * Import and cache a JsonWebKeyset\n * @param iss The issuer. Serves as the first-level cache key.\n * @param jwks The JsonWebKeyset to import.\n */\nexport async function importKey(iss: string, jwk: JsonWebKey): Promise<void> {\n if (jwk.kty !== 'RSA') {\n throw new Error(\n `Unsupported jwk key type (kty) \"${\n jwk.kty\n }\": Full JWK was ${JSON.stringify(jwk)}`\n );\n }\n // alg is not mandatory in a JWK but is available in the JWT, for now we default to\n // SHA-256 (RS256) because this is the most common but evaluating the key length\n // of the JWKS is probably an ideal way of identifying what the alg is.\n const hash = jwk.alg ? algToHash[jwk.alg] : 'SHA-256';\n if (!hash) {\n throw new Error(\n `Unsupported jwk Algorithm (alg) \"${\n jwk.alg\n }\": Full JWK was ${JSON.stringify(jwk)}`\n );\n }\n const key = await crypto.subtle.importKey(\n 'jwk',\n jwk,\n { name: 'RSASSA-PKCS1-v1_5', hash },\n false,\n ['verify']\n );\n let issuerKeys = importedKeys.get(iss);\n if (!issuerKeys) {\n issuerKeys = new Map();\n importedKeys.set(iss, issuerKeys);\n }\n issuerKeys.set(jwk.kid ?? 'default', key);\n}\n\n/**\n * Get the CryptoKey associated with the JWT's issuer.\n */\nexport async function getKey(decoded: DecodedJwt): Promise<CryptoKey> {\n const {\n header: { kid = 'default' },\n payload: { iss }\n } = decoded;\n\n let issuerKeys = importedKeys.get(iss);\n if (!issuerKeys) {\n const jwks = await getJwks(iss);\n await Promise.all(jwks.keys.map(jwk => importKey(iss, jwk)));\n issuerKeys = importedKeys.get(iss);\n }\n\n const key = issuerKeys?.get(kid);\n\n if (!key) {\n throw new Error(`Error jwk not found. iss: ${iss}; kid: ${kid};`);\n }\n\n return key;\n}\n"]}
@@ -1,3 +1,4 @@
1
1
  {
2
- "type": "module"
2
+ "type": "module",
3
+ "sideEffects": false
3
4
  }
@@ -7,3 +7,4 @@ export interface JwtParseOptions {
7
7
  skewMs?: number;
8
8
  }
9
9
  export declare function parseJwt({ jwt, issuer, audience, resolveKey, skewMs }: JwtParseOptions): Promise<JwtParseResult>;
10
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/parse.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAwB,cAAc,EAAE,MAAM,YAAY,CAAC;AAK9E,MAAM,WAAW,eAAe;IAI9B,GAAG,EAAE,MAAM,CAAC;IAOZ,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAK1B,QAAQ,EAAE,MAAM,CAAC;IASjB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAMhE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,wBAAsB,QAAQ,CAAC,EAC7B,GAAG,EACH,MAAM,EACN,QAAQ,EACR,UAAmB,EACnB,MAAsB,EACvB,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CA4M3C"}
package/dist/esm/parse.js CHANGED
@@ -185,3 +185,4 @@ export async function parseJwt({ jwt, issuer, audience, resolveKey = getKey, ske
185
185
  const { header, payload } = decoded;
186
186
  return { valid: true, header, payload };
187
187
  }
188
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/parse.ts"],"names":[],"mappings":"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","sourcesContent":["import { algs, algToHash } from './algs.js';\nimport { decodeJwt } from './decode.js';\nimport { getKey } from './jwks.js';\nimport { DecodedJwt, InvalidJwtReasonCode, JwtParseResult } from './types.js';\nimport { verifyJwtSignature } from './verify.js';\n\nconst defaultSkewMs = 60 * 1000;\n\nexport interface JwtParseOptions {\n /**\n * The JWT to parse.\n */\n jwt: string;\n\n /**\n * Permitted issuer(s) of the JWT. Used to validate the iss claim.\n * Note: if you're using the default resolveKey function, OIDC discovery will be used\n * to fetch the public key(s) for the issuer.\n */\n issuer: string | string[];\n\n /**\n * Expected audience of the JWT.\n */\n audience: string;\n\n /**\n * Given a decoded (but not fully verified) JWT, resolve the public key that\n * should be used to verify the signature. Typical implementations will use\n * the \"kid\" claim to look up the key in a JWKS endpoint or other key store.\n * If the key cannot be resolved, the function should return null.\n * @param decoded The decoded (but not fully verified / unsafe) JWT.\n */\n resolveKey?: (decoded: DecodedJwt) => Promise<CryptoKey | null>;\n\n /**\n * The maximum skew in milliseconds to allow when validating iat, nbf, and exp claims.\n * Defaults to 60 seconds.\n */\n skewMs?: number;\n}\n\n/**\n * Parse a JWT.\n */\nexport async function parseJwt({\n jwt,\n issuer,\n audience,\n resolveKey = getKey,\n skewMs = defaultSkewMs\n}: JwtParseOptions): Promise<JwtParseResult> {\n let decoded: DecodedJwt;\n try {\n decoded = decodeJwt(jwt);\n } catch {\n return {\n valid: false,\n reason: `Unable to decode JWT.`,\n reasonCode: InvalidJwtReasonCode.Other\n };\n }\n const { typ, alg } = decoded.header;\n if (typeof typ !== 'undefined' && typ !== 'JWT') {\n return {\n valid: false,\n reason: `Invalid JWT type ${JSON.stringify(typ)}. Expected \"JWT\".`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n if (!algToHash[alg]) {\n return {\n valid: false,\n reason: `Invalid JWT algorithm ${JSON.stringify(\n alg\n )}. Supported: ${algs}.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n\n const { sub, aud, iss, iat, exp, nbf } = decoded.payload;\n if (typeof sub !== 'string') {\n return {\n valid: false,\n reason: `Subject claim (sub) is required and must be a string. Received ${JSON.stringify(\n sub\n )}.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n\n if (typeof aud === 'string') {\n if (aud !== audience) {\n return {\n valid: false,\n reason: `Invalid JWT audience claim (aud) ${JSON.stringify(\n aud\n )}. Expected \"${audience}\".`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n } else if (\n Array.isArray(aud) &&\n aud.length > 0 &&\n aud.every(a => typeof a === 'string')\n ) {\n if (!aud.includes(audience)) {\n return {\n valid: false,\n reason: `Invalid JWT audience claim array (aud) ${JSON.stringify(\n aud\n )}. Does not include \"${audience}\".`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n } else {\n return {\n valid: false,\n reason: `Invalid JWT audience claim (aud) ${JSON.stringify(\n aud\n )}. Expected a string or a non-empty array of strings.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n\n if (!(iss === issuer || (Array.isArray(issuer) && issuer.includes(iss)))) {\n return {\n valid: false,\n reason: `Invalid JWT issuer claim (iss) ${JSON.stringify(\n decoded.payload.iss\n )}. Expected ${JSON.stringify(issuer)}.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n\n if (typeof exp !== 'number') {\n return {\n valid: false,\n reason: `Invalid JWT expiry date claim (exp) ${JSON.stringify(\n exp\n )}. Expected number.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n const currentDate = new Date(Date.now());\n const expiryDate = new Date(0);\n expiryDate.setUTCSeconds(exp);\n const expired = expiryDate.getTime() <= currentDate.getTime() - skewMs;\n if (expired) {\n return {\n valid: false,\n reason: `JWT is expired. Expiry date: ${expiryDate}; Current date: ${currentDate};`,\n reasonCode: InvalidJwtReasonCode.Expired,\n decoded\n };\n }\n\n if (nbf !== undefined) {\n if (typeof nbf !== 'number') {\n return {\n valid: false,\n reason: `Invalid JWT not before date claim (nbf) ${JSON.stringify(\n nbf\n )}. Expected number.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n const notBeforeDate = new Date(0);\n notBeforeDate.setUTCSeconds(nbf);\n const early = notBeforeDate.getTime() > currentDate.getTime() + skewMs;\n if (early) {\n return {\n valid: false,\n reason: `JWT cannot be used prior to not before date claim (nbf). Not before date: ${notBeforeDate}; Current date: ${currentDate};`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n }\n\n if (iat !== undefined) {\n if (typeof iat !== 'number') {\n return {\n valid: false,\n reason: `Invalid JWT issued at date claim (iat) ${JSON.stringify(\n iat\n )}. Expected number.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n const issuedAtDate = new Date(0);\n issuedAtDate.setUTCSeconds(iat);\n const postIssued = issuedAtDate.getTime() > currentDate.getTime() + skewMs;\n if (postIssued) {\n return {\n valid: false,\n reason: `JWT issued at date claim (iat) is in the future. Issued at date: ${issuedAtDate}; Current date: ${currentDate};`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n }\n\n let key: CryptoKey | null;\n try {\n key = await resolveKey(decoded);\n } catch (e) {\n return {\n valid: false,\n reason: `Error retrieving public key to verify JWT signature: ${\n e instanceof Error ? e.message : e\n }`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n if (!key) {\n return {\n valid: false,\n reason: `Unable to resolve public key to verify JWT signature.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n let signatureValid: boolean;\n try {\n signatureValid = await verifyJwtSignature(decoded, key);\n } catch {\n return {\n valid: false,\n reason: `Error verifying JWT signature.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n if (!signatureValid) {\n return {\n valid: false,\n reason: `JWT signature is invalid.`,\n reasonCode: InvalidJwtReasonCode.Other,\n decoded\n };\n }\n const { header, payload } = decoded;\n return { valid: true, header, payload };\n}\n"]}
@@ -69,3 +69,4 @@ export interface MtlsEndpointAliases {
69
69
  device_authorization_endpoint?: string;
70
70
  }
71
71
  export type JwtParseResult = ValidJwtParseResult | InvalidJwtParseResult;
72
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AASD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,UAAU,CAAC;IACpB,SAAS,EAAE,UAAU,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,oBAAoB,CAAC;IACjC,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAED,oBAAY,oBAAoB;IAC9B,KAAK,IAAI;IACT,OAAO,IAAI;CACZ;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,qCAAqC,CAAC,EAAE,MAAM,EAAE,CAAC;IACjD,gDAAgD,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5D,6CAA6C,CAAC,EAAE,MAAM,EAAE,CAAC;IACzD,wDAAwD,CAAC,EAAE,MAAM,EAAE,CAAC;IACpE,0CAA0C,CAAC,EAAE,MAAM,EAAE,CAAC;IACtD,qDAAqD,CAAC,EAAE,MAAM,EAAE,CAAC;IACjE,2CAA2C,CAAC,EAAE,MAAM,EAAE,CAAC;IACvD,qBAAqB,CAAC,EAAE,mBAAmB,CAAC;IAC5C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,CAAC;CACxC;AAED,MAAM,MAAM,cAAc,GAAG,mBAAmB,GAAG,qBAAqB,CAAC"}
package/dist/esm/types.js CHANGED
@@ -3,3 +3,4 @@ export var InvalidJwtReasonCode;
3
3
  InvalidJwtReasonCode[InvalidJwtReasonCode["Other"] = 0] = "Other";
4
4
  InvalidJwtReasonCode[InvalidJwtReasonCode["Expired"] = 1] = "Expired";
5
5
  })(InvalidJwtReasonCode || (InvalidJwtReasonCode = {}));
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAsDA,MAAM,CAAN,IAAY,oBAGX;AAHD,WAAY,oBAAoB;IAC9B,iEAAS,CAAA;IACT,qEAAW,CAAA;AACb,CAAC,EAHW,oBAAoB,KAApB,oBAAoB,QAG/B","sourcesContent":["export interface JwtPayload {\n iss: string;\n sub: string;\n aud: string | Array<string>;\n iat: number;\n exp: number;\n nbf?: number;\n jti?: string;\n}\n\nexport interface JwtHeader {\n typ?: string;\n alg: string;\n kid: string;\n jku?: string;\n}\n\nexport interface RawJwt {\n header: string;\n payload: string;\n signature: string;\n}\n\n/**\n * @typedef {object} DecodedJwt\n * @property {JwtHeader} header\n * @property {JwtPayload} payload\n * @property {string} signature\n * @property {RawJwt} raw\n */\nexport interface DecodedJwt {\n header: JwtHeader;\n payload: JwtPayload;\n signature: Uint8Array;\n raw: RawJwt;\n}\n\nexport interface JsonWebKeyset {\n keys: JsonWebKey[];\n}\n\nexport interface ValidJwtParseResult {\n valid: true;\n header: JwtHeader;\n payload: JwtPayload;\n}\n\nexport interface InvalidJwtParseResult {\n valid: false;\n reason: string;\n reasonCode: InvalidJwtReasonCode;\n decoded?: DecodedJwt;\n}\n\nexport enum InvalidJwtReasonCode {\n Other = 0,\n Expired = 1\n}\n\nexport interface IssuerMetadata {\n issuer: string;\n authorization_endpoint?: string;\n token_endpoint?: string;\n jwks_uri?: string;\n userinfo_endpoint?: string;\n revocation_endpoint?: string;\n end_session_endpoint?: string;\n registration_endpoint?: string;\n token_endpoint_auth_methods_supported?: string[];\n token_endpoint_auth_signing_alg_values_supported?: string[];\n introspection_endpoint_auth_methods_supported?: string[];\n introspection_endpoint_auth_signing_alg_values_supported?: string[];\n revocation_endpoint_auth_methods_supported?: string[];\n revocation_endpoint_auth_signing_alg_values_supported?: string[];\n request_object_signing_alg_values_supported?: string[];\n mtls_endpoint_aliases?: MtlsEndpointAliases;\n [key: string]: unknown;\n}\n\nexport interface MtlsEndpointAliases {\n token_endpoint?: string;\n userinfo_endpoint?: string;\n revocation_endpoint?: string;\n introspection_endpoint?: string;\n device_authorization_endpoint?: string;\n}\n\nexport type JwtParseResult = ValidJwtParseResult | InvalidJwtParseResult;\n"]}
@@ -1,2 +1,3 @@
1
1
  import { DecodedJwt } from './types.js';
2
2
  export declare function verifyJwtSignature(decoded: DecodedJwt, key: CryptoKey): Promise<boolean>;
3
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAMxC,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,SAAS,GACb,OAAO,CAAC,OAAO,CAAC,CAqBlB"}
@@ -1,5 +1,14 @@
1
+ import { algToHash } from './algs.js';
1
2
  export async function verifyJwtSignature(decoded, key) {
3
+ if (key.algorithm.name !== 'RSASSA-PKCS1-v1_5') {
4
+ throw new Error(`Unsupported key algorithm "${key.algorithm.name}": only RSASSA-PKCS1-v1_5 is supported.`);
5
+ }
6
+ const alg = decoded.header.alg;
7
+ if (!algToHash[alg]) {
8
+ throw new Error(`Unsupported JWT algorithm "${alg}": must be one of ${Object.keys(algToHash).join(', ')}.`);
9
+ }
2
10
  const encoder = new TextEncoder();
3
11
  const data = encoder.encode(`${decoded.raw.header}.${decoded.raw.payload}`);
4
- return crypto.subtle.verify('RSASSA-PKCS1-v1_5', key, decoded.signature, data);
12
+ return crypto.subtle.verify('RSASSA-PKCS1-v1_5', key, Uint8Array.from(decoded.signature), data);
5
13
  }
14
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/verify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAOtC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAmB,EACnB,GAAc;IAEd,IAAI,GAAG,CAAC,SAAS,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CACb,8BAA8B,GAAG,CAAC,SAAS,CAAC,IAAI,yCAAyC,CAC1F,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;IAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,8BAA8B,GAAG,qBAAqB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC3F,CAAC;IACJ,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAE5E,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CACzB,mBAAmB,EACnB,GAAG,EACH,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAClC,IAAI,CACL,CAAC;AACJ,CAAC","sourcesContent":["import { algToHash } from './algs.js';\nimport { DecodedJwt } from './types.js';\n\n/**\n * Verify the JWT's signature.\n * @param {DecodedJwt} decoded\n */\nexport async function verifyJwtSignature(\n decoded: DecodedJwt,\n key: CryptoKey\n): Promise<boolean> {\n if (key.algorithm.name !== 'RSASSA-PKCS1-v1_5') {\n throw new Error(\n `Unsupported key algorithm \"${key.algorithm.name}\": only RSASSA-PKCS1-v1_5 is supported.`\n );\n }\n const alg = decoded.header.alg;\n if (!algToHash[alg]) {\n throw new Error(\n `Unsupported JWT algorithm \"${alg}\": must be one of ${Object.keys(algToHash).join(', ')}.`\n );\n }\n const encoder = new TextEncoder();\n const data = encoder.encode(`${decoded.raw.header}.${decoded.raw.payload}`);\n\n return crypto.subtle.verify(\n 'RSASSA-PKCS1-v1_5',\n key,\n Uint8Array.from(decoded.signature),\n data\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cfworker/jwt",
3
- "version": "7.0.4",
3
+ "version": "7.0.5",
4
4
  "description": "Tiny lib for decoding JWTs and verifying signatures, using native crypto APIs",
5
5
  "keywords": [
6
6
  "jwt",
@@ -40,8 +40,9 @@
40
40
  ],
41
41
  "scripts": {
42
42
  "prepare": "tshy",
43
- "build": "tsc --build",
44
- "clean": "tsc --build --clean",
43
+ "build": "tshy",
44
+ "typecheck": "tsc --project tsconfig.json",
45
+ "clean": "tsc --build tsconfig.build.json --clean",
45
46
  "pretest": "esbuild test/test.ts --target=esnext --bundle --format=esm --conditions=worker,browser --outdir=dist-test --ignore-annotations",
46
47
  "test": "node ../../test.mjs"
47
48
  },
@@ -49,15 +50,16 @@
49
50
  "rfc4648": "^1.5.4"
50
51
  },
51
52
  "devDependencies": {
52
- "@types/chai": "^5.0.1",
53
+ "@types/chai": "^5.2.3",
53
54
  "@types/mocha": "^10.0.10",
54
- "chai": "^5.1.2",
55
- "esbuild": "^0.24.2",
56
- "mocha": "^11.1.0",
57
- "typescript": "^5.7.3",
58
- "wrangler": "^3.107.2"
55
+ "chai": "^6.3.0",
56
+ "esbuild": "^0.28.2",
57
+ "mocha": "^12.0.3",
58
+ "typescript": "^7.0.2",
59
+ "wrangler": "^4.156.0"
59
60
  },
60
61
  "tshy": {
62
+ "project": "./tsconfig.build.json",
61
63
  "exports": {
62
64
  "./package.json": "./package.json",
63
65
  ".": "./src/index.ts"