3.6 KiB
@suaveplan/api-auth-bearer-static — Static-token service auth
Package: @suaveplan/api-auth-bearer-static
Status: PROPOSED
Type: new-package
Stage: 4 (Base adapters) — see umbrella openspec/changes/api-plugin-foundation/
Why
Service-to-service callers (cron runners, sidecar daemons, internal admin tooling) often present a single static bearer token in lieu of a full JWT or OAuth flow. Per design doc §2.3, api-auth-bearer-static resolves these tokens against a fixed table: token → Principal. No provider, no DB lookup, no JWKS — just constant-time match.
Common in chained-resolver topologies: api-auth-jwt for users AND api-auth-bearer-static for service callers, first match wins. When paired with the host's admin API, this adapter SHOULD be gated by mutual-TLS (operator config) — the bearer token is necessary but not sufficient.
Stage 4 invariant: ships both direct and worker-proxy surfaces; both pass runAuthSessionConformance (§5.2a, §13.4).
What changes
Net-new package depending on @suaveplan/api-auth, @suaveplan/api-types, @suaveplan/api-worker-rpc, @suaveplan/crypto-utils (constant-time equality), @suaveplan/error, zod.
- ADDED:
createBearerStaticResolver(opts)— direct-surface factory. - ADDED:
createBearerStaticResolverWorkerProxy(port, opts)— proxy-surface factory. - ADDED:
BearerStaticResolverOptions— Zod schema withtokens: Array<{ token: string; principal: Principal; mtlsRequired?: boolean }>,headerName?: string(defaultAuthorization),prefix?: string(defaultBearer). - ADDED:
securitySchemeContribution()— OpenAPIsecuritySchemesentry for HTTP Bearer with custom scheme name. - ADDED:
AUTH_BEARER_STATIC_*error codes (AUTH_BEARER_STATIC_NO_TOKEN,AUTH_BEARER_STATIC_UNKNOWN_TOKEN,AUTH_BEARER_STATIC_MTLS_REQUIRED,AUTH_BEARER_STATIC_INVALID_OPTIONS). - ADDED: Optional mutual-TLS gate — when
mtlsRequired: truefor a token entry, the host MUST surface a verified client-cert subject; absence → reject. The host integration point isrequest.tls?.peerCertificate; this adapter checks for its presence and rejects otherwise.
Out of scope
- Token rotation — operators reload host config to swap tokens; this adapter is intentionally static.
- DB-backed token lookups — that's
api-auth-better-author a futureapi-auth-token-tableadapter. - Establishing the TLS context — the host's listener configures TLS; this adapter only reads what the listener attached.
Source mapping
Genesis-original. Source of design intent: docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md.
| Requirement | Design doc section |
|---|---|
| Service-to-service static tokens | §2.3 (api-auth-bearer-static bullet) |
| Optional mTLS gate | §2.3 (final paragraph) |
| Worker-proxy variant | §5.2a |
| Conformance both surfaces | §13.4 |
Verification approach
src/factory/create-bearer-static-resolver.test.ts— token match returns Principal; unknown token → null; missing token → null.src/factory/create-bearer-static-resolver.spec-conformance.test.ts—runAuthSessionConformance("bearer-static-direct", ...).src/proxy/create-bearer-static-resolver-worker-proxy.test.ts— proxy unit tests.src/proxy/create-bearer-static-resolver-worker-proxy.spec-conformance.test.ts—runAuthSessionConformance("bearer-static-worker-proxy", ...).src/mtls/mtls-gate.test.ts—mtlsRequired: truerejects when peerCertificate missing.src/constant-time/token-match.test.ts— constant-time comparison invariant (no early exit).
Migration impact
None — additive only.