# Extension points — auth0/node-jsonwebtoken

> Canonical page: https://codevetter.com/unpack/jsonwebtoken/extension-points

# Extension points — auth0/node-jsonwebtoken

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

This library has no plugin system by design — a JWT implementation with third-party extension hooks would be a security liability. What it does have are a handful of declarative tables that are the intended edit sites for new capability, and one genuine runtime hook. The tables are the two option schemas and the `options_to_payload` map in sign.js, the four algorithm arrays in verify.js, and the `allowedAlgorithmsForKeys`/`allowedCurves` matrices in `lib/validateAsymmetricKey.js` — adding an algorithm means touching all three files coherently. The one caller-facing hook is verify's function-valued `secretOrPublicKey`, which is where JWKS clients plug in. Feature detection for new Node capabilities follows a one-file-per-boolean convention in `lib/`.
- PRIMARY RUNTIME HOOK: `secretOrPublicKey` as a `(header, secretCallback)` function is the documented integration point for JWKS/`kid`-based key resolution; internally the static-key case is normalized into the same shape so there is exactly one code path after line 101. — [verify.js#L88-101](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L88-L101) [README.md#L138-139](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/README.md#L138-L139)
- Adding a new sign option means one entry in `sign_options_schema` with an `isValid` predicate and a `message` — the generic `validate(schema, allowUnknown, object, parameterName)` walker requires no other change, and unknown options are rejected because `validateOptions` passes `allowUnknown: false`. — [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)
- `registered_claims_schema` is the parallel table for payload claims and is validated with `allowUnknown: true`, so arbitrary custom claims pass through while `iat`/`exp`/`nbf` are type-enforced — this asymmetry is the extension point for application-specific claims. — [sign.js#L36-40](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L36-L40) [sign.js#L65-67](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L65-L67) [test/claim-private.tests.js](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/claim-private.tests.js)
- `options_to_payload` is a two-column map from option name to claim name; adding a new registered-claim shortcut is a one-line addition there, and the conflict-detection and copy logic applies automatically. — [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)
- `options_for_objects` is the companion list declaring which options are meaningless for non-object payloads; any new object-only option must be added here too or it will be silently accepted on a string payload. — [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)
- Algorithm support is defined in four arrays: `SUPPORTED_ALGS` (sign.js) and `PUB_KEY_ALGS` / `EC_KEY_ALGS` / `RSA_KEY_ALGS` / `HS_ALGS` (verify.js). A new algorithm requires edits in both files plus `allowedAlgorithmsForKeys`. — [sign.js#L14-17](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/sign.js#L14-L17) [verify.js#L11-19](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L11-L19) [lib/validateAsymmetricKey.js#L4-8](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/validateAsymmetricKey.js#L4-L8)
- `allowedAlgorithmsForKeys` maps `asymmetricKeyType` → permitted `alg` values and is the single authority on key/algorithm pairing; an unrecognized key type throws `Unknown key type "<type>"`, so new key types must be registered here or they are rejected outright. — [lib/validateAsymmetricKey.js#L4-30](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/validateAsymmetricKey.js#L4-L30) [test/verify.tests.js#L272-282](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/verify.tests.js#L272-L282)
- `allowedCurves` maps ES algorithms to required named curves and is the place to add a curve; it is consulted only under `ASYMMETRIC_KEY_DETAILS_SUPPORTED`. — [lib/validateAsymmetricKey.js#L10-14](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/validateAsymmetricKey.js#L10-L14) [lib/validateAsymmetricKey.js#L39-48](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/validateAsymmetricKey.js#L39-L48)
- New Node-version feature gates follow a one-module-per-flag convention: a three-line file exporting `semver.satisfies(process.version, '<range>')`, consumed as a module-scope constant. Three such files already exist. — [lib/psSupported.js](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/psSupported.js) [lib/asymmetricKeyDetailsSupported.js](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/asymmetricKeyDetailsSupported.js) [lib/rsaPssKeyDetailsSupported.js](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/rsaPssKeyDetailsSupported.js)
- New error types extend the hierarchy by the ES5 pattern in `lib/NotBeforeError.js`: call `JsonWebTokenError.call(this, message)`, set `this.name`, add the payload field, then `prototype = Object.create(JsonWebTokenError.prototype)` and restore `constructor`. New types must also be re-exported from `index.js` to be reachable. — [lib/NotBeforeError.js#L1-13](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/NotBeforeError.js#L1-L13) [lib/TokenExpiredError.js#L1-13](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/lib/TokenExpiredError.js#L1-L13) [index.js#L5-7](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/index.js#L5-L7)
- New verify-time claim checks slot into the linear block between `jws.verify` and the return, following the established `if (options.X) { if (payload.y !== options.X) return done(new JsonWebTokenError(...)) }` shape used by issuer/subject/jwtid/nonce. — [verify.js#L209-235](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/verify.js#L209-L235)
- Test convention for new options/claims: add a `test/option-<name>.test.js` or `test/claim-<name>.test.js` file that uses `testUtils.signJWTHelper`/`verifyJWTHelper` plus `asyncCheck`, so sync/async parity is enforced for free. — [test/option-nonce.test.js](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/option-nonce.test.js) [test/option-maxAge.test.js](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/option-maxAge.test.js) [test/claim-jti.test.js](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/claim-jti.test.js) [test/test-utils.js#L120-125](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/test/test-utils.js#L120-L125)
- Release automation is itself extensible through `.releaserc.json`'s plugin array; the `@semantic-release/exec` entry is where additional pre-publish gates (currently `git diff --exit-code` and the ReversingLabs scan) would be added. — [.releaserc.json#L20-30](https://github.com/auth0/node-jsonwebtoken/blob/b924272f29192e12926b5414546f7c5bfcc9579d/.releaserc.json#L20-L30)

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)
