jwt-ts — API
base64urlEncode
Section titled “base64urlEncode”export function base64urlEncode(input: Buffer | string): stringbase64urlDecode
Section titled “base64urlDecode”export function base64urlDecode(input: string): BufferderToJose
Section titled “derToJose”export function derToJose(signature: Buffer, keySize: number): BufferjoseToDer
Section titled “joseToDer”export function joseToDer(signature: Buffer): BufferJWTError
Section titled “JWTError”export class JWTError extends Error { constructor(message: string) { super(message); this.name = 'JWTError'; }}InvalidSignatureError
Section titled “InvalidSignatureError”export class InvalidSignatureError extends JWTError { constructor() { super('Invalid signature'); this.name = 'InvalidSignatureError'; }}TokenExpiredError
Section titled “TokenExpiredError”export class TokenExpiredError extends JWTError { constructor() { super('Token expired'); this.name = 'TokenExpiredError'; }}NotBeforeError
Section titled “NotBeforeError”export class NotBeforeError extends JWTError { constructor() { super('Token not active yet (nbf)'); this.name = 'NotBeforeError'; }}JWTClaimValidationError
Section titled “JWTClaimValidationError”export class JWTClaimValidationError extends JWTError { constructor(message: string) { super(message); this.name = 'JWTClaimValidationError'; }}JoseHeaderError
Section titled “JoseHeaderError”export class JoseHeaderError extends JWTError { constructor(message: string) { super(message); this.name = 'JoseHeaderError'; }}JoseContext
Section titled “JoseContext”export type JoseContext = 'jws' | 'jwe' | 'jwt';HeaderValidationOptions
Section titled “HeaderValidationOptions”export interface HeaderValidationOptions { context: JoseContext; enforceUnknown?: 'reject' | 'ignore'; allowedExtensions?: Set<string>; expectedTyp?: string | null;}validateJoseHeaders
Section titled “validateJoseHeaders”export function validateJoseHeaders(header: { [k: string]: any } | undefined, opts: HeaderValidationOptions)HeaderValidator
Section titled “HeaderValidator”export class HeaderValidator { static validate(header: { [k: string]: any } | undefined, opts: HeaderValidationOptions) { if (!header) return; if (typeof header !== 'object') throw new JoseHeaderError('JOSE header must be an object');
const allowed = allowedParamsFor(opts.context); const allowedExt = opts.allowedExtensions || new Set<string>(); const enforceUnknown = opts.enforceUnknown ?? 'ignore';
if (header.crit !== undefined) { if (!Array.isArray(header.crit) || !header.crit.every((i: any) => typeof i === 'string')) { throw new JoseHeaderError('Invalid "crit" header: must be array of strings'); } for (const critName of header.crit as string[]) { if (!Object.prototype.hasOwnProperty.call(header, critName)) { throw new JoseHeaderError(`crit declares ${critName} but it is not present in header`); } if (!allowed.has(critName) && !allowedExt.has(critName)) { throw new JoseHeaderError(`Unsupported critical header parameter: ${critName}`); } } }
for (const k of Object.keys(header)) { if (allowed.has(k)) continue; if (allowedExt.has(k)) continue; if (k === 'x5t#S256') continue; if (enforceUnknown === 'reject') { throw new JoseHeaderError(`Unknown JOSE header parameter: ${k}`); } }
if (opts.expectedTyp) { if (header.typ !== undefined && header.typ !== opts.expectedTyp) { throw new JoseHeaderError(`Unexpected typ header: expected ${opts.expectedTyp}`); } }
if (header.cty !== undefined && typeof header.cty !== 'string') { throw new JoseHeaderError('cty header must be a string when present'); } }}export type Alg = | 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512' | 'PS256' | 'PS384' | 'PS512' | 'ES256' | 'ES256K' | 'ES384' | 'ES512' | 'EdDSA' | 'none';Signer
Section titled “Signer”export interface Signer { sign(payload: Buffer, key: crypto.KeyLike | Buffer | string): Buffer | Promise<Buffer>; verify(payload: Buffer, signature: Buffer, key: crypto.KeyLike | Buffer | string): boolean | Promise<boolean>;}getSigner
Section titled “getSigner”export function getSigner(alg: Alg): SignerJWAFactory
Section titled “JWAFactory”export class JWAFactory { static getSigner(alg: Alg): Signer { switch (alg) { case 'HS256': return HMAC('sha256'); case 'HS384': return HMAC('sha384'); case 'HS512': return HMAC('sha512');
case 'RS256': return RSA('sha256', crypto.constants.RSA_PKCS1_PADDING); case 'RS384': return RSA('sha384', crypto.constants.RSA_PKCS1_PADDING); case 'RS512': return RSA('sha512', crypto.constants.RSA_PKCS1_PADDING);
case 'PS256': return RSA_PSS('sha256'); case 'PS384': return RSA_PSS('sha384'); case 'PS512': return RSA_PSS('sha512');
case 'ES256': return ECDSA('sha256', 256); case 'ES256K': return ECDSA('sha256', 256); // secp256k1 case 'ES384': return ECDSA('sha384', 384); case 'ES512': return ECDSA('sha512', 521);
case 'EdDSA': return { sign(payload: Buffer, key) { return (crypto as any).sign(null, payload, key as crypto.KeyLike) as Buffer; }, verify(payload: Buffer, signature: Buffer, key) { return (crypto as any).verify(null, payload, key as crypto.KeyLike, signature) as boolean; } };
case 'none': return { sign() { return Buffer.alloc(0); }, verify() { return true; } };
default: throw new Error(`Unsupported alg ${alg}`); } }}encryptCompact
Section titled “encryptCompact”export async function encryptCompact(plaintext: Buffer | string, recipient: { alg: string; key: any }, headerInput: any = {}, enc: 'A128GCM' | 'A256GCM' | 'A128CBC-HS256' | 'A256CBC-HS512' = 'A256GCM')decryptCompact
Section titled “decryptCompact”export async function decryptCompact(token: string, keyOrLookup: any | ((header: any) => any | Promise<any>))encryptGeneral
Section titled “encryptGeneral”export async function encryptGeneral(plaintext: Buffer | string, recipients: Array<{ alg: string; key: any; header?: any; }>, protectedHeader: any = {}, unprotectedHeader: any = {}, enc: 'A128GCM' | 'A256GCM' | 'A128CBC-HS256' | 'A256CBC-HS512' = 'A256GCM')decryptGeneral
Section titled “decryptGeneral”export async function decryptGeneral(jwe: any, keyOrLookup: any | ((header: any) => any | Promise<any>))export type JWK = { [key: string]: any };jwkToKeyObject
Section titled “jwkToKeyObject”export function jwkToKeyObject(jwk: JWK): crypto.KeyObjectkeyObjectToJwk
Section titled “keyObjectToJwk”export function keyObjectToJwk(key: crypto.KeyObject): JWKjwkToPEM
Section titled “jwkToPEM”export function jwkToPEM(jwk: JWK, opts: { private?: boolean } = {}): stringpemToJwk
Section titled “pemToJwk”export function pemToJwk(pem: string): JWKjwkThumbprint
Section titled “jwkThumbprint”export function jwkThumbprint(jwk: JWK, hash = 'sha256'): stringJWKManager
Section titled “JWKManager”export class JWKManager { jwkToKeyObject(jwk: JWK) { if (!jwk || typeof jwk !== 'object') throw new TypeError('Invalid JWK'); const hasPrivate = !!jwk.d; try { if (hasPrivate) return crypto.createPrivateKey({ key: jwk as any, format: 'jwk' }); return crypto.createPublicKey({ key: jwk as any, format: 'jwk' }); } catch (e) { throw new Error('Failed to convert JWK to KeyObject: ' + (e as Error).message); } }
keyObjectToJwk(key: crypto.KeyObject) { try { return key.export({ format: 'jwk' }) as JWK; } catch (e) { throw new Error('Failed to export KeyObject to JWK: ' + (e as Error).message); } }
jwkToPEM(jwk: JWK, opts: { private?: boolean } = {}) { const keyObj = this.jwkToKeyObject(jwk); if (opts.private) return keyObj.export({ type: 'pkcs8', format: 'pem' }) as string; return keyObj.export({ type: 'spki', format: 'pem' }) as string; }
pemToJwk(pem: string) { const keyObj = crypto.createPublicKey(pem); try { return keyObj.export({ format: 'jwk' }) as JWK; } catch (e) { const priv = crypto.createPrivateKey(pem); return priv.export({ format: 'jwk' }) as JWK; } }
jwkThumbprint(jwk: JWK, hash = 'sha256') { const kty = jwk.kty; let members: string[] = []; if (kty === 'RSA') members = ['e', 'kty', 'n']; else if (kty === 'EC') members = ['crv', 'kty', 'x', 'y']; else if (kty === 'OKP') members = ['crv', 'kty', 'x']; else throw new Error('Unsupported JWK kty for thumbprint'); const obj: any = {}; for (const m of members) obj[m] = jwk[m]; const json = JSON.stringify(obj); const h = crypto.createHash(hash).update(json).digest(); return h.toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); }}export type JWKS = { keys: JWK[] };getJwkByKid
Section titled “getJwkByKid”export function getJwkByKid(jwks: JWKS | JWK[], kid?: string, alg?: string): JWK | undefinedresolveJwkFromHeader
Section titled “resolveJwkFromHeader”export function resolveJwkFromHeader(jwks: JWKS | JWK[], header: { kid?: string; alg?: string }): JWK | undefinedJWKSResolver
Section titled “JWKSResolver”export class JWKSResolver { static getJwkByKid(jwks: JWKS | JWK[], kid?: string, alg?: string) { const keys = Array.isArray(jwks) ? jwks : (jwks && jwks.keys) || []; if (!kid && !alg) return keys[0]; let candidates = keys; if (kid) candidates = candidates.filter(k => k.kid === kid); if (alg) candidates = candidates.filter(k => { if (!k.alg) return true; return k.alg === alg || k.alg === alg.replace('-', ''); }); return candidates[0]; }
static resolveJwkFromHeader(jwks: JWKS | JWK[], header: { kid?: string; alg?: string }) { return JWKSResolver.getJwkByKid(jwks, header.kid, header.alg); }}JWSHeader
Section titled “JWSHeader”export type JWSHeader = { alg: Alg; typ?: string; cty?: string; kid?: string; b64?: boolean; crit?: string[];[key: string]: any };SignerInput
Section titled “SignerInput”export interface SignerInput { key: any; // PEM, KeyObject or JWK protectedHeader?: Partial<JWSHeader>; header?: { [key: string]: any } | undefined; // unprotected header}signCompact
Section titled “signCompact”export async function signCompact(payload: object | string | Buffer, signer: SignerInput): Promise<string>verifyCompact
Section titled “verifyCompact”export async function verifyCompact(token: string, keyOrLookup: any | ((header: JWSHeader) => any | Promise<any>), options: { expectedAlg?: Alg; expectedTyp?: string; detachedPayload?: Buffer | string } = {}): Promise<{ header: JWSHeader; payload: any }>GeneralJWS
Section titled “GeneralJWS”export interface GeneralJWS { protected?: { [key: string]: any }; header?: { [key: string]: any }; signature: string;}signGeneral
Section titled “signGeneral”export async function signGeneral(payload: object | string | Buffer, signers: SignerInput[], opts: { detached?: boolean } = {}): Promise<{ payload: string; signatures: GeneralJWS[] }>verifyGeneral
Section titled “verifyGeneral”export async function verifyGeneral(obj: { payload: string; signatures: GeneralJWS[] }, keyOrLookup: any | ((header: any) => any | Promise<any>), options: { expectedTyp?: string; detachedPayload?: Buffer | string } = {}): Promise<{ payload: any; verified: boolean }>JWTPayload
Section titled “JWTPayload”export type JWTPayload = { [key: string]: any };JWTHeader
Section titled “JWTHeader”export type JWTHeader = { alg: Alg; typ?: string; kid?: string;[key: string]: any };SignOptions
Section titled “SignOptions”export interface SignOptions { alg?: Alg; typ?: string; kid?: string; iat?: boolean; // add issued at exp?: number | null; // seconds from now}VerifyOptions
Section titled “VerifyOptions”export interface VerifyOptions { algorithms?: Alg[]; issuer?: string | string[]; subject?: string | string[]; audience?: string | string[]; jti?: string; typ?: string; // expected typ header ignoreExpiration?: boolean; clockTolerance?: number; // seconds}export async function sign(payload: JWTPayload, key: any, options: SignOptions = {}): Promise<string>decode
Section titled “decode”export function decode(token: string, options: { complete?: boolean } = {}): anyverify
Section titled “verify”export async function verify(token: string, key: any | ((header: JWTHeader) => any | Promise<any>), options: VerifyOptions = {}): Promise<JWTPayload>