# Feature catalog — auth0/node-jsonwebtoken

> Canonical page: https://codevetter.com/unpack/jsonwebtoken/feature-catalog

# Feature catalog — auth0/node-jsonwebtoken

Scanned commit b924272f29192e12926b5414546f7c5bfcc9579d (2026-06-25). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

The user-facing surface is three functions, each with a dual sync/async calling convention selected by whether a trailing callback is supplied. `sign` turns a payload plus key into a compact JWS, mapping option names onto registered claim names and computing time-based claims. `verify` is the security-critical path: it re-decodes, resolves a key (possibly via an async key-lookup callback for JWKS/kid workflows), enforces an algorithm allow-list, checks key/alg compatibility, verifies the signature, then runs seven independent claim checks. `decode` is the deliberately unauthenticated escape hatch. Twelve signing algorithms plus `none` are supported, and a set of explicit backwards-compatibility escape valves (`allowInsecureKeySizes`, `allowInvalidAsymmetricKeyTypes`) let callers opt out of the newer hardening.
- `jwt.sign(payload, secretOrPrivateKey, [options, callback])` supports thirteen options validated by `sign_options_schema`: `expiresIn`, `notBefore`, `audience`, `algorithm`, `header`, `encoding`, `issuer`, `subject`, `jwtid`, `noTimestamp`, `keyid`, `mutatePayload`, `allowInsecureKeySizes`, `allowInvalidAsymmetricKeyTypes` — and rejects any key not in that schema with `"<key>" is not allowed in "options"`. — [sign.js#L19-34](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L19-L34) [sign.js#L42-63](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L42-L63)
- Four sign options are sugar that write registered claims, via the `options_to_payload` table: `audience`→`aud`, `issuer`→`iss`, `subject`→`sub`, `jwtid`→`jti`. Supplying both the option and the raw claim is an error (`Bad "options.<x>" option. The payload already has an "<claim>" property.`). — [sign.js#L69-74](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L69-L74) [sign.js#L217-225](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L217-L225)
- Non-object payloads (strings, numbers, Buffers) are supported for signing but reject the seven object-only options listed in `options_for_objects` with `invalid <opts> option for <typeof> payload`; a Buffer payload round-trips as its string form. — [sign.js#L76-84](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L76-L84) [sign.js#L152-160](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L152-L160) [test/buffer.tests.js#L1-10](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/buffer.tests.js#L1-L10) [test/non_object_values.tests.js#L6-18](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/non_object_values.tests.js#L6-L18)
- `mutatePayload: false` (the default) shallow-clones the payload with `Object.assign({}, payload)` before adding `iat`/`exp`/`nbf`, which is what makes signing a frozen or sealed payload work. — [sign.js#L149-151](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L149-L151) [test/issue_147.tests.js#L6-11](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/issue_147.tests.js#L6-L11)
- `options.encoding` (default `utf8`) is passed through to `jws`, so `{encoding: 'binary'}` produces a differently-encoded payload segment for non-ASCII characters. — [sign.js#L227](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L227) [sign.js#L246](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L246) [test/encoding.tests.js#L11-25](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/encoding.tests.js#L11-L25)
- `jwt.verify(token, secretOrPublicKey, [options, callback])` supports thirteen options: `algorithms`, `audience`, `complete`, `issuer`, `jwtid`, `ignoreExpiration`, `ignoreNotBefore`, `subject`, `clockTolerance`, `maxAge`, `clockTimestamp`, `nonce`, `allowInvalidAsymmetricKeyTypes`. — [verify.js#L45-57](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L45-L57) [verify.js#L176-249](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L176-L249) [README.md#L145-165](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/README.md#L145-L165)
- `secretOrPublicKey` may be a key-lookup function `(header, cb)` — the JWKS/`kid` integration point — but only when a callback is also supplied; otherwise verify fails with `verify must be called asynchronous if secret or public key is provided as a callback`. — [verify.js#L88-99](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L88-L99) [verify.js#L101-103](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L101-L103)
- Audience matching accepts a string, a `RegExp`, or an array of either, and matches if ANY token `aud` entry matches ANY expected audience — an any-to-any `some`/`some` cross product. — [verify.js#L194-207](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L194-L207) [README.md#L151-152](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/README.md#L151-L152)
- `clockTolerance` (seconds of slack) and `clockTimestamp` (override for "now") apply to `nbf`, `exp`, and `maxAge` uniformly; `clockTimestamp` must be a number or verify fails early with `clockTimestamp must be a number`. — [verify.js#L45-47](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L45-L47) [verify.js#L57](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L57) [verify.js#L180](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L180) [verify.js#L189](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L189) [verify.js#L246](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L246)
- `maxAge` is an independent expiry ceiling computed from `payload.iat`, requires a numeric `iat` (`iat required when maxAge is specified`), and cannot loosen `exp` — a token past `exp` still fails even with `maxAge: '1000y'`. — [verify.js#L237-249](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L237-L249) [test/verify.tests.js#L251-269](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/verify.tests.js#L251-L269)
- `complete: true` on either `verify` or `decode` returns `{header, payload, signature}` instead of the bare payload — this is how callers reach `kid` and `alg` for key selection. — [verify.js#L251-259](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L251-L259) [decode.js#L19-28](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/decode.js#L19-L28)
- `jwt.decode(token, options)` performs no signature verification at all, and silently swallows a `JSON.parse` failure on the payload — returning the raw string payload rather than throwing. — [decode.js#L3-17](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/decode.js#L3-L17)
- Unsigned (`alg: none`) tokens are supported on both sides but require explicit opt-in on verify: `please specify "none" in "algorithms" to verify unsigned tokens`, and passing a key alongside a signature-less token yields `jwt signature is required`. — [verify.js#L106-118](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L106-L118) [test/verify.tests.js#L32-80](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/verify.tests.js#L32-L80)
- Two named backwards-compatibility escape hatches exist and are documented as discouraged: `allowInsecureKeySizes` (permits RSA modulus < 2048) and `allowInvalidAsymmetricKeyTypes` (skips the `validateAsymmetricKey` gate). — [sign.js#L132-137](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L132-L137) [sign.js#L177-183](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L177-L183) [verify.js#L154-160](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L154-L160) [README.md#L38](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/README.md#L38) [README.md#L165](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/README.md#L165)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
