3.1 KiB
jwt
Purpose
Provides minimal JWT decoding utilities for extracting and validating ID-token claims on the client side. Signature verification requires fetching the authorization server's JWKS endpoint and is deliberately out of scope — this module focuses on the claim-level checks that can be performed without cryptographic key material: issuer, audience, expiry, and nonce.
Separating JWT decoding from signature verification follows the principle of least authority: most OAuth 2.0 client use-cases need only claim extraction for session management, and those that require full verification can layer a JWKS-backed verifier on top.
Features
decodeJwt— splits a JWT and base64url-decodes the header and payload; returns typedJwtHeaderandIdTokenClaims.validateIdTokenClaims— verifiesiss,aud,exp(with configurable clock skew), and optionalnonce.- Throws
OAuthClientError(INVALID_ID_TOKEN)with structured context on every failure path.
Usage: Basic Example
import { decodeJwt } from "@suaveplan/oauth-client/utils/jwt";
const { header, claims } = decodeJwt(tokenSet.idToken!);
console.log(claims.sub); // subject identifier
console.log(claims.email); // user email (if present)
Usage: Advanced Example
import { decodeJwt, validateIdTokenClaims } from "@suaveplan/oauth-client/utils/jwt";
const { claims } = decodeJwt(tokenSet.idToken!);
validateIdTokenClaims(claims, {
issuer: "https://accounts.google.com",
audience: "my-client-id",
nonce: storedNonce,
clockSkewSeconds: 60,
});
// Safe to trust claims after validation passes
const userId = claims.sub;
API Reference
decodeJwt(token: string): { header: JwtHeader; claims: IdTokenClaims; raw: { header: string; payload: string; signature: string } }
Decodes a JWT string without verifying its signature.
- Throws
OAuthClientError(INVALID_ID_TOKEN)when the token does not have exactly three.-delimited parts or when either the header or payload is not valid base64url-encoded JSON.
validateIdTokenClaims(claims: IdTokenClaims, options): void
Validates standard OIDC ID-token claims.
options.issuer— expectedissvalue; must match exactly.options.audience— expectedaudvalue; must be present in theaudarray.options.nonce?— when provided, must matchclaims.nonce.options.clockSkewSeconds?— tolerance for clock drift, defaults to 30.options.nowSeconds?— override for the current time (seconds since epoch); useful in tests.- Throws
OAuthClientError(INVALID_ID_TOKEN)for any failed check.
Implementation Notes
The decodeJwt function uses base64UrlDecode from the pkce utility to avoid introducing a second base64url implementation. The TextDecoder API is universally available in all targeted runtimes. Claims are typed as IdTokenClaims which uses an index signature [key: string]: unknown to allow non-standard claims without compromising the strict types of standard fields. Clock-skew tolerance applies only to the exp check (not iat) to avoid accepting tokens from the future.