auth0/node-jsonwebtoken
There are exactly two input boundaries — the caller-supplied `(payload | jwtString, key, options)` tuple — and one output boundary, either a returned/thrown value or a `(err, result)` callback invocation. No state is owned across calls: the library is entirely stateless, with the only module-level mutable structures being the algorithm allow-list arrays built at require time. The central transform on both paths is key normalization: whatever the caller passes (string, Buffer, PEM, JWK-ish object) is funnelled through `crypto.createPrivateKey`/`createPublicKey` with a `createSecretKey` fallback into a `KeyObject`, and every downstream decision reads `key.type`, `key.asymmetricKeyType`, and `key.asymmetricKeyDetails` off that normalized object. Claim data flows one way on sign (options → payload properties → JWS) and one way on verify (JWS → decoded payload → claim assertions → returned payload).
- On sign, key material normalization is a try/catch cascade: if not already a `KeyObject`, attempt `createPrivateKey(secretOrPrivateKey)`, fall back to `createSecretKey(Buffer.from(...))` for strings, and on double failure emit `secretOrPrivateKey is not valid key material`.
- Verify mirrors that cascade with `createPublicKey` then `createSecretKey`, producing `secretOrPublicKey is not valid key material` — this is what converts a hostile object with a throwing `toString` into a clean error instead of arbitrary execution.
- The JWS header is assembled by `Object.assign` with a fixed precedence: computed `{alg, typ, kid}` first (alg defaults to `HS256`, `typ` is `'JWT'` only for object payloads, `kid` comes from `options.keyid`), then `options.header` spread last so it can override any of them including `alg`.
- A single `timestamp` value — `payload.iat || Math.floor(Date.now()/1000)` — is computed once and is the base for both `nbf` and `exp`, guaranteeing the three time claims are internally consistent within one sign call.
- On verify, the token is parsed twice: once shallowly as `jwtString.split('.')` for arity (`jwt malformed` when length !== 3) and signature-presence checks on `parts[2]`, and once fully through `decode(jwtString, {complete: true})`.
- `options` is defensively shallow-cloned on entry to verify (`Object.assign({}, options)`) specifically because the function later writes `options.algorithms` when the caller omitted it — caller-supplied objects are never mutated.
- When `options.algorithms` is absent, the allow-list is derived from the normalized key: `secret`→HS_ALGS, `rsa`/`rsa-pss`→RSA_KEY_ALGS, `ec`→EC_KEY_ALGS, everything else→PUB_KEY_ALGS. This binds the accepted alg set to the key material, not to the token.
- The token-supplied `header.alg` flows into `jws.verify(jwtString, decodedToken.header.alg, secretOrPublicKey)`, but only after passing the allow-list membership check and the key-type compatibility check — the ordering at lines 144→152→165 is the whole defense.
- The verified `payload` object returned to the caller is the same object produced by `decode`, not a copy — all seven claim checks read from it without transforming it, so callers receive attacker-influenced data verbatim (the README explicitly warns to sanitize it).
- Both functions funnel every error through a single sink — `failure(err)` in sign and `done(err, data)` in verify — which dispatches to `callback(err)` when async or `throw err` when sync, so sync and async modes are guaranteed to produce identical errors.
- `decode` normalizes the payload channel: `jws.decode` may return a string payload, which `decode` opportunistically `JSON.parse`s and keeps only if the result is a non-null object — otherwise the string passes through unchanged.
- `timespan(time, iat)` is the shared conversion from relative to absolute time on both paths: it feeds `payload.nbf`/`payload.exp` on sign and `maxAgeTimestamp` on verify, using `ms()` for strings and plain addition for numbers.
- The only file-system reads in the entire repo are in tests, loading PEM fixtures from `test/*.pem` — the library itself performs zero file or network I/O.