verifyToken()
Signature
Section titled “Signature”async verifyToken<T extends TokenPayload = TokenPayload>( token: string,): Promise<VerifyResult<T>>Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
token | string | JWT access token from Authorization: Bearer <token> header |
Return type
Section titled “Return type”type VerifyResult<T> = | { ok: true; data: T } | { ok: false; error: SdkError };The method never throws. All errors are returned via the Result type.
const result = await ca.verifyToken(token);
if (result.ok) { const { userId, email, tenantId, sessionId } = result.data; // User is authenticated} else { const { code, message, suggestion, docs_url } = result.error; // Handle error — see Error Codes reference}Generic typing
Section titled “Generic typing”Pass a custom type to extend the default payload:
interface MyPayload extends TokenPayload { role: string; permissions: string[];}
const result = await ca.verifyToken<MyPayload>(token);if (result.ok) { console.log(result.data.role); // Type-safe access}TokenPayload
Section titled “TokenPayload”The default decoded token payload:
interface TokenPayload { userId: string; // from JWT 'sub' claim email: string; tenantId: string; // from JWT 'tenant_id' claim sessionId: string; // from JWT 'sid' claim iss: string; // Issuer: 'rakomi.com' aud: string; // Audience exp: number; // Expiration (Unix timestamp) iat: number; // Issued at (Unix timestamp) jti: string; // Unique token ID session?: SessionMetadata; // Session expiry metadata (always present for user tokens) token?: TokenMetadata; // Token TTL metadata}
interface SessionMetadata { expiresAt: string; // ISO 8601 — from JWT exp claim maxLifetimeExpiresAt?: string; // ISO 8601 — present only for tenants with custom max lifetime policy isExpiringSoon: boolean; // true when min(token TTL, max lifetime remaining) < 300 seconds}
interface TokenMetadata { expiresIn: number; // Remaining seconds until token expiry (computed at verify time, clamped to 0)}Session expiry metadata
Section titled “Session expiry metadata”session.isExpiringSoon is true when the effective session lifetime (the smaller of token TTL and tenant max lifetime) is under 5 minutes. Use this to build server-side “session expiring soon” warnings without additional clock checks:
const result = await ca.verifyToken(token);if (result.ok) { if (result.data.session?.isExpiringSoon) { // Add warning header for the frontend res.setHeader('X-Session-Expiring-Soon', '1'); }}session.maxLifetimeExpiresAt is only present for tenants that have configured a custom session max lifetime (shorter than the platform default). Unlike token expiry, this limit cannot be extended by refresh — the user will be signed out at this absolute time.
JWKS caching behavior
Section titled “JWKS caching behavior”- Lazy initialization — JWKS is fetched on the first
verifyToken()call, not at construction - Single-entry cache — exactly 1 JWKS entry is cached, replaced atomically on refresh
- Cache-Control respected — the SDK honors the
Cache-Controlheader from the JWKS response - Automatic refresh — when a token’s
kiddoesn’t match the cached key, the SDK refetches JWKS once before returning an error
Clock tolerance
Section titled “Clock tolerance”The clockTolerance config option (default: 30 seconds, max: 120 seconds) allows for small clock differences between servers.
const ca = new RakomiClient({ apiKey: 'akm_live_xxx', clockTolerance: 60, // Allow 60 seconds of clock drift});Error codes
Section titled “Error codes”| Code | When |
|---|---|
token/expired | Token’s exp claim is in the past |
token/invalid_signature | Signature doesn’t match any JWKS key |
token/malformed | Not a valid JWT format |
token/invalid_algorithm | Algorithm is not RS256 |
token/missing_claims | Required claims (sub, tenant_id, etc.) missing |
token/invalid_issuer | Issuer doesn’t match rakomi.com |
token/not_yet_valid | Token’s nbf claim is in the future |
See Error Codes for full details with suggestions and fix commands.