Token Validation
Overview
Token validation is the core function of @authrim/server. The validateToken() method performs a complete validation pipeline — parsing the JWT, fetching the signing key, verifying the signature, and checking all standard claims.
validateToken API
const result = await authrim.validateToken(token, options?);Parameters
| Parameter | Type | Description |
|---|---|---|
token | string | The raw JWT access token (without the Bearer prefix) |
options | TokenValidationOptions | Optional validation options |
TokenValidationOptions
interface TokenValidationOptions { requiredScopes?: string[]; requiredClaims?: string[];}| Option | Type | Description |
|---|---|---|
requiredScopes | string[] | Scopes that must be present in the token’s scope claim |
requiredClaims | string[] | Claim names that must exist in the token payload |
Return Value: ValidatedToken
interface ValidatedToken { claims: AccessTokenClaims; token: string; tokenType: 'Bearer' | 'DPoP'; expiresIn?: number;}| Field | Type | Description |
|---|---|---|
claims | AccessTokenClaims | Parsed and validated JWT claims |
token | string | The original token string |
tokenType | 'Bearer' | 'DPoP' | Detected token type based on claims |
expiresIn | number | undefined | Seconds until the token expires (calculated from exp) |
AccessTokenClaims
interface AccessTokenClaims { iss: string; sub: string; aud: string | string[]; exp: number; iat: number; nbf?: number; jti?: string; scope?: string; client_id?: string; cnf?: { jkt?: string }; [key: string]: unknown; // Custom claims}Validation Pipeline
The SDK validates tokens through the following pipeline. Each step must pass for the token to be accepted:
flowchart TD
A["Receive JWT String"] --> B["Size Check
(max 8 KB)"]
B --> C["Parse JWT
(Header + Payload + Signature)"]
C --> D["Algorithm Check
(reject alg: none)"]
D --> E["Fetch Signing Key
(JWKS by kid)"]
E --> F["Verify Signature
(RS/PS/ES/EdDSA)"]
F --> G["Validate iss
(timing-safe)"]
G --> H["Validate aud
(timing-safe)"]
H --> I["Validate exp
(+ clock tolerance)"]
I --> J["Validate nbf
(+ clock tolerance)"]
J --> K["Validate iat
(not in future)"]
K --> L["Check Required Scopes"]
L --> M["Check Required Claims"]
M --> N["Detect Token Type
(Bearer vs DPoP)"]
N --> O["Return ValidatedToken"]
If any step fails, the SDK throws a specific error. See the Error Types section below.
Supported Algorithms
The SDK supports the following JWS algorithms for signature verification:
| Algorithm | Key Type | Curve / Size | Description |
|---|---|---|---|
| RS256 | RSA | 2048+ bits | RSASSA-PKCS1-v1_5 with SHA-256 |
| RS384 | RSA | 2048+ bits | RSASSA-PKCS1-v1_5 with SHA-384 |
| RS512 | RSA | 2048+ bits | RSASSA-PKCS1-v1_5 with SHA-512 |
| PS256 | RSA | 2048+ bits | RSASSA-PSS with SHA-256 |
| PS384 | RSA | 2048+ bits | RSASSA-PSS with SHA-384 |
| PS512 | RSA | 2048+ bits | RSASSA-PSS with SHA-512 |
| ES256 | EC | P-256 | ECDSA with SHA-256 |
| ES384 | EC | P-384 | ECDSA with SHA-384 |
| ES512 | EC | P-521 | ECDSA with SHA-512 |
| EdDSA | OKP | Ed25519 | Edwards-curve Digital Signature |
Claims Validation Details
Issuer (iss)
The iss claim must exactly match one of the configured issuer values. Comparison uses a timing-safe algorithm to prevent side-channel attacks.
// Single issuerconst authrim = new AuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com',});
// Multiple issuersconst authrim = new AuthrimServer({ issuer: [ 'https://auth.example.com', 'https://auth.partner.com', ], audience: 'https://api.example.com',});Audience (aud)
The aud claim must contain at least one of the configured audience values. The aud claim can be a single string or an array of strings. All comparisons are timing-safe.
// Token with aud: "https://api.example.com" — matches// Token with aud: ["https://api.example.com", "other"] — matches// Token with aud: "https://other.example.com" — rejectedExpiration (exp)
The exp claim is checked against the current time plus clockToleranceSeconds:
token is valid if: exp + clockToleranceSeconds > nowWith the default tolerance of 60 seconds, a token that expired up to 60 seconds ago is still accepted.
Not Before (nbf)
If present, the nbf claim is checked against the current time minus clockToleranceSeconds:
token is valid if: nbf - clockToleranceSeconds <= nowIssued At (iat)
The iat claim is sanity-checked to ensure the token was not issued in the future (with clock tolerance):
token is valid if: iat - clockToleranceSeconds <= nowScope Validation
Enforce required scopes using the requiredScopes option:
// Require specific scopesconst result = await authrim.validateToken(token, { requiredScopes: ['read:users', 'write:users'],});The SDK checks that all specified scopes are present in the token’s scope claim (space-delimited string). If any required scope is missing, an InsufficientScopeError is thrown.
Bearer vs DPoP Auto-Detection
The SDK automatically detects the token type based on the cnf (confirmation) claim:
- If the token contains
cnf.jkt(JWK Thumbprint), the token is classified asDPoP - Otherwise, the token is classified as
Bearer
const result = await authrim.validateToken(token);
if (result.tokenType === 'DPoP') { // This token is sender-constrained — validate the DPoP proof too await authrim.validateDPoP(dpopProof, { accessTokenHash: computeHash(token), expectedThumbprint: result.claims.cnf!.jkt!, method: 'GET', url: 'https://api.example.com/resource', });}For full DPoP validation, see DPoP Validation.
Code Examples
Basic Token Validation
import { AuthrimServer } from '@authrim/server';
const authrim = new AuthrimServer({ issuer: 'https://auth.example.com', audience: 'https://api.example.com',});await authrim.init();
try { const result = await authrim.validateToken(accessToken); console.log('User:', result.claims.sub); console.log('Scopes:', result.claims.scope); console.log('Expires in:', result.expiresIn, 'seconds');} catch (error) { console.error('Token validation failed:', error.message);}With Required Scopes
try { const result = await authrim.validateToken(accessToken, { requiredScopes: ['read:orders', 'write:orders'], }); // Token is valid and has both scopes} catch (error) { if (error.name === 'InsufficientScopeError') { // Token is valid but missing required scopes — return 403 return res.status(403).json({ error: 'insufficient_scope' }); } // Token is invalid — return 401 return res.status(401).json({ error: 'invalid_token' });}Accessing Custom Claims
Tokens may contain custom claims added by the authorization server (e.g., roles, tenant ID). Access them through the claims object:
const result = await authrim.validateToken(accessToken);
// Access custom claims with type assertionconst roles = result.claims['roles'] as string[];const tenantId = result.claims['tenant_id'] as string;
// Or use a type parameter for full type safetyinterface MyTokenClaims extends AccessTokenClaims { roles: string[]; tenant_id: string;}
const claims = result.claims as MyTokenClaims;console.log(claims.roles); // ['admin', 'user']console.log(claims.tenant_id); // 'tenant-123'Error Types
| Error | Description | HTTP Status |
|---|---|---|
InsecureAlgorithmError | Token uses alg: none or an unsupported algorithm | 401 |
InvalidSignatureError | Signature verification failed | 401 |
TokenExpiredError | Token exp claim has passed (beyond clock tolerance) | 401 |
TokenNotYetValidError | Token nbf claim is in the future (beyond clock tolerance) | 401 |
InvalidIssuerError | Token iss does not match configured issuer(s) | 401 |
InvalidAudienceError | Token aud does not match configured audience(s) | 401 |
InsufficientScopeError | Token is missing one or more required scopes | 403 |
MissingClaimError | Token is missing a required claim | 401 |
JwksError | Failed to fetch or process JWKS | 500 |
TokenSizeLimitError | Token exceeds 8 KB size limit | 401 |
Next Steps
- DPoP Validation — Validate sender-constrained tokens with DPoP proof verification
- JWKS Management — Key discovery, caching, and rotation internals
- Introspection & Revocation — Query and revoke tokens at the authorization server
- Security Considerations — Production security checklist and best practices