{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * json-web-token — JWT encode/decode with zero runtime dependencies.\n *\n * v4 highlights:\n *   - Fixes CVE-2023-48238 (algorithm confusion). The library now\n *     rejects any token whose algorithm family does not match the\n *     key it was handed. PEM-encoded keys can only be used with the\n *     asymmetric algorithms; plain secrets can only be used with the\n *     HMAC algorithms. Optional `algorithms` allowlist on `decode`\n *     adds a second layer for safety-conscious callers.\n *   - Zero runtime deps (Node's `crypto` + `Buffer` only). Drops\n *     base64-url, is.object, json-parse-safe, xtend.\n *   - HMAC verification uses `crypto.timingSafeEqual` instead of a\n *     plain `===` compare, so an attacker can't timing-leak which\n *     prefix bytes of the signature match.\n *   - `alg: 'none'` and unknown algorithms continue to be rejected.\n *   - Synchronous result-object API only — callbacks dropped:\n *       encode(key, data, [algorithm])  →  { error, value }\n *       decode(key, token, [options])   →  { error, value, header? }\n *     Wrap in a Promise yourself if you want async ergonomics.\n */\n\nimport {\n\tcreateHmac,\n\tcreateSign,\n\tcreateVerify,\n\ttimingSafeEqual,\n} from \"node:crypto\";\n\nconst algorithms = {\n\tHS256: { hash: \"sha256\", type: \"hmac\" },\n\tHS384: { hash: \"sha384\", type: \"hmac\" },\n\tHS512: { hash: \"sha512\", type: \"hmac\" },\n\tRS256: { hash: \"RSA-SHA256\", type: \"sign\" },\n} as const;\n\ntype AlgorithmName = keyof typeof algorithms;\ntype AlgorithmSpec = (typeof algorithms)[AlgorithmName];\n\nexport class JWTError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"JWTError\";\n\t}\n}\n\nexport interface JWTHeader {\n\ttyp?: string;\n\talg?: string;\n\t[key: string]: unknown;\n}\n\nexport interface EncodeResult {\n\terror: JWTError | null;\n\tvalue: string | null;\n}\n\nexport interface DecodeResult {\n\terror: JWTError | null;\n\tvalue: unknown;\n\theader?: JWTHeader;\n}\n\nexport interface DecodeOptions {\n\t/**\n\t * Optional whitelist of acceptable algorithms (e.g. `[\"RS256\"]`).\n\t * When provided, `decode` rejects any token whose `header.alg` is\n\t * not in the list. The key-type vs algorithm-type guard runs\n\t * regardless of this option.\n\t */\n\talgorithms?: string[];\n}\n\ntype Key = string | Buffer;\n\ninterface PayloadWrapper {\n\tpayload: unknown;\n\theader?: Record<string, unknown>;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\ntype KeyKind = \"asymmetric\" | \"secret\";\n\n/**\n * Classify a key as asymmetric (PEM-encoded RSA/EC/Ed key material) or\n * a plain HMAC secret. The classifier is conservative: anything that\n * doesn't start with a PEM banner is treated as a secret.\n *\n * This is the root of the CVE-2023-48238 fix — we use the result to\n * refuse the HMAC verify path when the caller passed an asymmetric\n * key (which is what the algorithm-confusion attack exploits).\n */\nfunction inferKeyKind(key: Key): KeyKind {\n\tconst head = Buffer.isBuffer(key)\n\t\t? key.subarray(0, 11).toString(\"ascii\")\n\t\t: key.trimStart().slice(0, 11);\n\treturn head === \"-----BEGIN \" ? \"asymmetric\" : \"secret\";\n}\n\nfunction algorithmMatchesKey(alg: AlgorithmSpec, kind: KeyKind): boolean {\n\treturn alg.type === \"hmac\" ? kind === \"secret\" : kind === \"asymmetric\";\n}\n\nfunction isWrapper(value: unknown): value is PayloadWrapper {\n\treturn isPlainObject(value) && \"payload\" in value && value.payload != null;\n}\n\nfunction fail(message: string): EncodeResult {\n\treturn { error: new JWTError(message), value: null };\n}\n\nfunction failDecode(message: string): DecodeResult {\n\treturn { error: new JWTError(message), value: null };\n}\n\nexport function getAlgorithms(): AlgorithmName[] {\n\treturn Object.keys(algorithms) as AlgorithmName[];\n}\n\nexport function encode(\n\tkey: Key,\n\tdata: unknown,\n\talgorithm: string = \"HS256\"\n): EncodeResult {\n\tconst defaultHeader = { typ: \"JWT\", alg: algorithm };\n\tconst payload: unknown = isWrapper(data) ? data.payload : data;\n\tconst header: Record<string, unknown> =\n\t\tisWrapper(data) && isPlainObject(data.header)\n\t\t\t? { ...data.header, ...defaultHeader }\n\t\t\t: defaultHeader;\n\n\tconst validationError = encodeValidations(key, payload, algorithm);\n\tif (validationError) return fail(validationError);\n\n\tconst algSpec = algorithms[algorithm as AlgorithmName];\n\tif (!algorithmMatchesKey(algSpec, inferKeyKind(key))) {\n\t\treturn fail(\n\t\t\talgSpec.type === \"hmac\"\n\t\t\t\t? \"Algorithm/key mismatch: HMAC algorithm requires a plain secret, not an asymmetric key.\"\n\t\t\t\t: \"Algorithm/key mismatch: asymmetric algorithm requires a PEM-encoded key, not a plain secret.\"\n\t\t);\n\t}\n\n\tconst headerPart = encodeBase64Url(JSON.stringify(header));\n\tconst payloadPart = encodeBase64Url(JSON.stringify(payload));\n\tconst signingInput = `${headerPart}.${payloadPart}`;\n\tconst signature = sign(algSpec, key, signingInput);\n\treturn { error: null, value: `${signingInput}.${signature}` };\n}\n\nexport function decode(\n\tkey: Key,\n\ttoken: string,\n\toptions: DecodeOptions = {}\n): DecodeResult {\n\tif (!key || !token) return failDecode(\"The key and token are mandatory!\");\n\n\tconst parts = token.split(\".\");\n\tif (parts.length !== 3) {\n\t\treturn failDecode(\"The JWT should consist of three parts!\");\n\t}\n\n\tconst header = parseJSONOrNull(decodeBase64Url(parts[0] as string));\n\tconst payload = parseJSONOrNull(decodeBase64Url(parts[1] as string));\n\n\tif (!isPlainObject(header)) {\n\t\treturn failDecode(\"The algorithm is not supported!\");\n\t}\n\n\tconst algName = header.alg;\n\tconst algorithm =\n\t\ttypeof algName === \"string\"\n\t\t\t? algorithms[algName as AlgorithmName]\n\t\t\t: undefined;\n\tif (!algorithm) return failDecode(\"The algorithm is not supported!\");\n\n\tif (options.algorithms && !options.algorithms.includes(algName as string)) {\n\t\treturn failDecode(\"The algorithm is not in the allowlist.\");\n\t}\n\n\t// CVE-2023-48238 fix: refuse to verify when the algorithm family\n\t// disagrees with the key kind. This blocks the classic RS256→HS256\n\t// confusion attack where an attacker re-signs a token with HMAC\n\t// using the server's RSA public key as the secret.\n\tif (!algorithmMatchesKey(algorithm, inferKeyKind(key))) {\n\t\treturn failDecode(\n\t\t\talgorithm.type === \"hmac\"\n\t\t\t\t? \"Algorithm/key mismatch: refusing to verify an HMAC signature with an asymmetric key.\"\n\t\t\t\t: \"Algorithm/key mismatch: refusing to verify an asymmetric signature with a plain secret.\"\n\t\t);\n\t}\n\n\tconst ok = verify(\n\t\talgorithm,\n\t\tkey,\n\t\t`${parts[0]}.${parts[1]}`,\n\t\tparts[2] as string\n\t);\n\treturn {\n\t\terror: ok ? null : new JWTError(\"Invalid key!\"),\n\t\tvalue: payload,\n\t\theader: header as JWTHeader,\n\t};\n}\n\nfunction encodeValidations(\n\tkey: Key,\n\tpayload: unknown,\n\talgorithm: string\n): string | null {\n\tif (!key || payload == null) return \"The key and payload are mandatory!\";\n\tif (isPlainObject(payload) && Object.keys(payload).length === 0) {\n\t\treturn \"The payload is an empty object!\";\n\t}\n\tif (!algorithms[algorithm as AlgorithmName]) {\n\t\treturn \"The algorithm is not supported!\";\n\t}\n\treturn null;\n}\n\nfunction sign(alg: AlgorithmSpec, key: Key, input: string): string {\n\tif (alg.type === \"hmac\") {\n\t\treturn createHmac(alg.hash, key).update(input).digest(\"base64url\");\n\t}\n\treturn createSign(alg.hash).update(input).sign(key, \"base64url\");\n}\n\nfunction verify(\n\talg: AlgorithmSpec,\n\tkey: Key,\n\tinput: string,\n\tsignature: string\n): boolean {\n\tif (alg.type === \"hmac\") {\n\t\tconst expected = sign(alg, key, input);\n\t\tconst a = Buffer.from(expected, \"utf8\");\n\t\tconst b = Buffer.from(signature, \"utf8\");\n\t\tif (a.length !== b.length) return false;\n\t\treturn timingSafeEqual(a, b);\n\t}\n\treturn createVerify(alg.hash)\n\t\t.update(input)\n\t\t.verify(key, signature, \"base64url\");\n}\n\nfunction encodeBase64Url(input: string): string {\n\treturn Buffer.from(input, \"utf8\").toString(\"base64url\");\n}\n\nfunction decodeBase64Url(input: string): string {\n\treturn Buffer.from(input, \"base64url\").toString(\"utf8\");\n}\n\nfunction parseJSONOrNull(input: string): unknown {\n\ttry {\n\t\treturn JSON.parse(input);\n\t} catch {\n\t\treturn null;\n\t}\n}\n"]}