UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

90 lines (89 loc) • 4.63 kB
/** * verify/jwtCore — the one place a signed token is checked, shared by every * inbound verifier (`jwksIdentity`, `oidcIdentity`). * * Pattern: shared kernel. Two verifiers that each spelled "signature, issuer, * audience, expiry" would be two answers to one question, and the day * one of them required `exp` and the other did not is the day a token * with no lifetime got through the lenient one. * Role: load `jose`, map its failures onto the library's failure words, and * hand back the verified claim set. Nothing here reads WHO the token * is about: that is each verifier's own business. * * ── Every token expires ───────────────────────────────────────────────────── * `jose` checks `exp` only when a token carries one (6.2.8, * `validateClaimsSet`). A signed token WITHOUT `exp` would verify and never * expire — another token type signed by the same keys, or a proxy that forgot * the claim. So `exp` is required twice: `requiredClaims: ['exp']` for `jose`, * and a check of the returned claims for any other backend (a stub, a fork) * that ignores that option. Refused as `unverifiable`: the token is not one * this door reads, and `expired` would tell the client to refresh. */ /** * The slice of `jose` the inbound verifiers use — declared STRUCTURALLY, so a * stub, a pinned fork, or a future major satisfies it without this package * taking a hard type dependency on an optional peer. (The `UnpdfBackend` * precedent.) */ export interface JoseBackend { createRemoteJWKSet(url: URL, options?: Record<string, unknown>): unknown; jwtVerify(token: string, key: unknown, options?: Record<string, unknown>): Promise<{ payload: Record<string, unknown>; }>; } /** Raised when a token must be verified and `jose` is not installed. */ export declare class MissingJwksSupportError extends Error { readonly code: "ERR_MISSING_JWKS_SUPPORT"; constructor(); } /** * The asymmetric families. Symmetric algorithms (`HS*`) are deliberately NOT * here: with a JWKS the key is public, and a verifier that accepts an HMAC alg * over a published key is the classic algorithm-confusion forgery. */ export declare const DEFAULT_ALGORITHMS: readonly string[]; type JoseFailure = 'expired' | 'not-yet-valid' | 'wrong-audience' | 'wrong-issuer' | 'unverifiable' | 'keys-unavailable'; /** * `jose`'s stable error codes → this library's failure vocabulary. * * Mapped by CODE STRING rather than by `instanceof`, and that is the load- * bearing choice: the error classes are not on `jose`'s main entry point (they * live under `jose/errors`), the codes are documented as stable, and a string * comparison survives a duplicated copy of the library in a `node_modules` tree * — which `instanceof` famously does not. * * Every code is one the verifiers have SEEN the installed library produce; the * pin test (test/adapters/identity/jwks.test.ts) reproduces each one. */ export declare function joseFailureOf(err: unknown): JoseFailure; /** What {@link verifySignedToken} checks the token against. */ export interface SignedTokenChecks { /** Accepted `iss` values — compared exactly. */ readonly issuer: string | readonly string[]; /** Accepted `aud` values. */ readonly audience: string | readonly string[]; readonly algorithms: readonly string[]; /** Seconds of clock skew tolerated on `exp`/`nbf`. */ readonly clockToleranceSeconds?: number; /** The verifier's name, for the 503 — never its configuration. */ readonly verifierName: string; } /** * Check one token's signature and registered claims, and hand back its claim * set — or throw {@link IdentityNotVerifiedError} (the caller's token) / * {@link VerifierUnavailableError} (this deployment's key set). * * Neither error carries the token, the claims or the library's own text, and * the original is deliberately NOT attached as `cause`: a cause travels into * every serializer that walks own properties. */ export declare function verifySignedToken(jose: JoseBackend, keys: unknown, token: string, checks: SignedTokenChecks): Promise<Record<string, unknown>>; /** * Load `jose`, or refuse by name. * * `jose` v6 is ESM-only, so a dynamic import is tried first and the CJS require * is the fallback — one of the two works on every runtime this package * supports. (The `unpdf` loader's shape, for the same reason.) */ export declare function loadJose(): Promise<JoseBackend>; export {};