Files
2026-05-27 23:29:53 +01:00

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 with tokens: Array<{ token: string; principal: Principal; mtlsRequired?: boolean }>, headerName?: string (default Authorization), prefix?: string (default Bearer).
  • ADDED: securitySchemeContribution() — OpenAPI securitySchemes entry 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: true for a token entry, the host MUST surface a verified client-cert subject; absence → reject. The host integration point is request.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-auth or a future api-auth-token-table adapter.
  • 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: true rejects when peerCertificate missing.
  • src/constant-time/token-match.test.ts — constant-time comparison invariant (no early exit).

Migration impact

None — additive only.