/** * JWT Token Utilities * * Handles JWT generation and validation for SERV sessions * Uses HMAC-SHA256 for simplicity; can be upgraded to RSA/EC for production */ import type { Session, SessionToken, Tenant, User, Membership } from '../types/index.js'; export interface JwtConfig { /** * Signing secret for HMAC algorithms (HS256/384/512). Min 32 bytes * recommended. Ignored when algorithm is an asymmetric variant. */ secret: string; /** Token issuer (e.g., 'https://serv.example.com') */ issuer: string; /** Default token expiry in seconds */ expirySeconds: number; /** * Algorithm to use. Asymmetric variants require `privateKey` (PEM) for * signing and optionally `publicKey` (PEM) for verification. If the * public key is omitted it's derived from the private key. */ algorithm: 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'ES256'; /** PEM-encoded private key. Required for RS256/ES256. */ privateKey?: string; /** PEM-encoded public key; derived from privateKey if omitted. */ publicKey?: string; /** Key identifier for `kid` header. Optional; useful during key rotation. */ kid?: string; } export declare class JwtService { private config; private privateKey?; private publicKey?; constructor(config: Partial & { issuer: string; secret?: string; }); /** * Export the public JWK for publication at `/.well-known/jwks.json`. * Only meaningful for asymmetric algorithms. */ exportJwk(): Record | null; /** * Generate an OAuth access token JWT for the token endpoint. * * This is a lower-level variant of `generateSessionToken` that accepts * the minimal fields needed for an OAuth 2.1 bearer token: `sub`, `scope`, * `client_id`, `tenant_id`, plus a TTL. No `Session` object required. */ generateAccessToken(args: { sub: string; tenantId: string; scope: string; clientId: string; expiresInSeconds: number; now?: Date; /** Optional jti; random if omitted. */ jti?: string; }): string; /** * Sign a custom payload (used by RFC 8693 token exchange, where the * caller fully controls the claim set including `aud`, `act`, etc.). * Caller is responsible for including `iss`, `exp`, `iat`. */ exchangeSign(payload: Record): string; /** * Generate an OpenID Connect id_token per OIDC Core §3.1.3.7. * * Identity assertion about the end-user. Issued when `openid` scope is * granted at /token. Signed with the same key/algorithm as access tokens. * `azp` (authorized party) claim identifies the client that requested it. */ generateIdToken(args: { sub: string; tenantId: string; clientId: string; expiresInSeconds: number; now?: Date; /** Optional extra claims (email, name, etc.) surfaced from the profile. */ profile?: Record; /** Optional nonce echoed from the authorize request. */ nonce?: string; }): string; /** * Generate a session token */ generateSessionToken(session: Session, tenant: Tenant, user?: User, membership?: Membership): string; /** * Verify and decode a token */ verifySessionToken(token: string): SessionToken | null; /** * Decode without verification (for debugging) */ decode(token: string): SessionToken | null; /** * Build audience URI for a tenant */ private buildAudience; /** * Sign a payload and return JWT */ private sign; /** * Verify a JWT and return payload */ private verify; /** * Create JWS signature. HMAC for symmetric algs, RSA-PSS / ECDSA for asymmetric. */ private createSignature; private hashName; } /** * Generate a code verifier for PKCE */ export declare function generateCodeVerifier(): string; /** * Generate a code challenge from a verifier (RFC 7636 §4.2, S256 method) * code_challenge = BASE64URL-ENCODE(SHA256(code_verifier)) */ export declare function generateCodeChallenge(verifier: string): string; /** * Verify a code verifier against a challenge */ export declare function verifyCodeChallenge(verifier: string, challenge: string): boolean; export interface OAuthState { sessionId: string; elicitationId: string; photonId: string; provider: string; nonce: string; timestamp: number; } /** * Encode OAuth state for authorization request */ export declare function encodeOAuthState(state: OAuthState, secret: string): string; /** * Decode and verify OAuth state */ export declare function decodeOAuthState(encoded: string, secret: string): OAuthState | null; /** * Convert a DER-encoded ECDSA signature (Node's default output from * `createSign().sign()`) into the IEEE-P1363 r||s encoding required by * RFC 7518 §3.4 for JWS ES256/ES384/ES512. * * DER layout: 0x30 [totalLen] 0x02 [rLen] [r...] 0x02 [sLen] [s...] * r and s are encoded as signed integers — DER prepends 0x00 if the high * bit of the first byte would otherwise make them negative. P1363 strips * that padding and left-zero-pads each component to `componentLen` bytes. */ declare function derToP1363(der: Buffer, componentLen: number): Buffer; /** * Convert a P1363 r||s signature into DER for Node's `verifier.verify()`. * Inverse of `derToP1363`. Used on the verify path so signatures received * in spec-compliant JWS form can still be handed to Node's DER-only API. */ declare function p1363ToDer(p1363: Buffer): Buffer; /** Internal exports for tests only. */ export declare const __test_ecdsa__: { derToP1363: typeof derToP1363; p1363ToDer: typeof p1363ToDer; }; export declare function getJwtService(config?: Partial & { secret: string; issuer: string; }): JwtService; export declare function initJwtService(config: Partial & { secret: string; issuer: string; }): JwtService; /** Reset the singleton — for testing only. */ export declare function resetJwtService(): void; export {}; //# sourceMappingURL=jwt.d.ts.map