Files
skills/docs/identity/auth/jwt-tenant/src/jwks/jwks-endpoint/jwks-endpoint.md
2026-05-29 08:20:56 +01:00

3.2 KiB

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

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

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<JWKS> — Returns active public keys as a JWKS. Caches result unless config.includeExpired is true.
  • handleRequest(request): Promise<JWKSResponse> — 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.