# jwks-endpoint _(no submodules)_ ## Purpose Provides a framework-agnostic JWKS endpoint backed by a `TenantKeyStore`. The endpoint serialises active public keys from the store into a `{ keys: JWK[] }` JSON Web Key Set and exposes an HTTP response builder that any framework can consume. An internal cache reduces key-store reads on high-traffic endpoints, with the TTL controlled by `cacheMaxAge`. ## Features - `JWKSEndpoint` class with configurable cache TTL and injectable clock - `getJWKS(config?)` — fetches active public keys and returns a `JWKS` object - `handleRequest(request)` — returns a framework-agnostic `{ status, body, headers }` response - `clearCache()` — invalidates the internal JWKS cache on demand - `formatJWKSResponse(keys)` — standalone pure function to wrap JWK arrays - `createJWKSEndpoint(options)` — factory function - `includeExpired` option to bypass cache and include all keys ## Usage: Basic Example ```ts import { InMemoryKeyStore } from "@suaveplan/jwt-tenant/jwks/in-memory-key-store"; import { JWKSEndpoint } from "@suaveplan/jwt-tenant/jwks/jwks-endpoint"; import { generateKeyPair } from "@suaveplan/jwt-tenant/keys/key-generator"; const store = new InMemoryKeyStore(); const kp = await generateKeyPair("EdDSA"); await store.addKey(kp); const endpoint = new JWKSEndpoint({ keyStore: store }); const response = await endpoint.handleRequest(null); // response.status === 200 // JSON.parse(response.body).keys.length === 1 ``` ## Usage: Advanced Example ```ts import { JWKSEndpoint } from "@suaveplan/jwt-tenant/jwks/jwks-endpoint"; // Use in a Hono or Express route app.get("/.well-known/jwks.json", async (req, res) => { const response = await endpoint.handleRequest(req); res.status(response.status) .set(response.headers) .send(response.body); }); // Force cache invalidation after key rotation await store.addKey(newKeyPair); endpoint.clearCache(); ``` ## API Reference ### `JWKSEndpoint` Constructor: `new JWKSEndpoint(options: JWKSEndpointOptions)`. - `options.keyStore` — `TenantKeyStore` implementation - `options.cacheMaxAge` — cache TTL in milliseconds (default 5 min) - `options.clock` — injectable clock for cache expiry #### Methods - **`getJWKS(config?): Promise`** — Returns active public keys as a JWKS. Caches result unless `config.includeExpired` is `true`. - **`handleRequest(request): Promise`** — Returns `{ status: 200, body: string, headers }`. The `request` parameter is accepted for interface compatibility. - **`clearCache(): void`** — Resets the internal cache immediately. ### `formatJWKSResponse(keys: JWK[]): JWKS` Pure function that wraps a `JWK[]` in a `{ keys }` envelope. ### `createJWKSEndpoint(options): JWKSEndpoint` Factory function; equivalent to `new JWKSEndpoint(options)`. ## Implementation Notes The cache uses a simple timestamp check against `clock()`. Cache invalidation on key rotation must be explicit (`clearCache()`). The `handleRequest` `_request` parameter is intentionally ignored — the endpoint serves the same JWKS for all requests. In production, mount the endpoint behind a CDN with short TTLs for automatic key rotation propagation.