3.7 KiB
Capability Spec Delta: api-auth-bearer-static (api-auth-bearer-static)
Package: @suaveplan/api-auth-bearer-static
Status: PROPOSED
ADDED Requirements
Requirement: Static token table resolves to Principal
The package SHALL match incoming bearer tokens against a fixed table supplied at construction time. A matching token produces the associated Principal; an unknown token produces null. Token comparison MUST be constant-time so an attacker cannot probe valid token prefixes via timing.
Scenario: known token returns its Principal
- WHEN a request carries
Authorization: Bearer T1AND the table contains{ token: "T1", principal: P } - THEN
resolveSession()returnsP
Scenario: unknown token returns null
- WHEN a request carries
Authorization: Bearer NOT_IN_TABLE - THEN
resolveSession()returnsnullAND emitsAUTH_BEARER_STATIC_UNKNOWN_TOKENon the failure counter
Scenario: token match is constant-time
- WHEN two unknown tokens of equal length are compared against the table
- THEN the comparison loop runs to completion for both (no early exit on first mismatched byte)
Verified by: src/factory/create-bearer-static-resolver.test.ts::"known token returns its Principal" AND src/factory/create-bearer-static-resolver.test.ts::"unknown token returns null and increments failure counter" AND src/constant-time/token-match.test.ts::"comparison runs to completion regardless of mismatch position"
Requirement: Optional mutual-TLS gate
A token entry MAY carry mtlsRequired: true. When set, the resolver MUST require the request to carry a verified peer certificate (surfaced by the host listener); absence MUST produce null and emit AUTH_BEARER_STATIC_MTLS_REQUIRED.
Scenario: mTLS-gated token rejects requests without peer cert
- WHEN an mTLS-gated token is presented but
request.tls.peerCertificateis undefined - THEN
resolveSession()returnsnullAND emitsAUTH_BEARER_STATIC_MTLS_REQUIRED
Scenario: mTLS-gated token accepts requests with peer cert
- WHEN the same token is presented AND
request.tls.peerCertificateis present - THEN
resolveSession()returns the Principal
Verified by: src/mtls/mtls-gate.test.ts::"rejects mtls-required token without peer certificate" AND src/mtls/mtls-gate.test.ts::"accepts mtls-required token with peer certificate"
Requirement: Direct and worker-proxy surfaces both pass conformance
The adapter SHALL pass runAuthSessionConformance under both surfaces.
Scenario: direct surface conforms
- WHEN
runAuthSessionConformance("bearer-static-direct", () => createBearerStaticResolver(...))runs - THEN every invariant passes
Scenario: worker-proxy surface conforms
- WHEN
runAuthSessionConformance("bearer-static-worker-proxy", ...)runs over a realMessageChannel - THEN every invariant passes
Verified by: src/factory/create-bearer-static-resolver.spec-conformance.test.ts::"bearer-static-direct conforms to AuthSession contract" AND src/proxy/create-bearer-static-resolver-worker-proxy.spec-conformance.test.ts::"bearer-static-worker-proxy conforms to AuthSession contract"
Requirement: Options Zod-validated
BearerStaticResolverOptions MUST be Zod-validated. Empty tokens array OR a non-string token entry MUST throw AUTH_BEARER_STATIC_INVALID_OPTIONS at factory construction.
Scenario: empty tokens array throws
- WHEN
createBearerStaticResolver({ tokens: [] }) - THEN a
SuaveplanErrorwith codeAUTH_BEARER_STATIC_INVALID_OPTIONSis thrown synchronously
Verified by: src/options/bearer-static-resolver-options.test.ts::"throws on empty tokens array"