# 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 T1` AND the table contains `{ token: "T1", principal: P }` - **THEN** `resolveSession()` returns `P` #### Scenario: unknown token returns null - **WHEN** a request carries `Authorization: Bearer NOT_IN_TABLE` - **THEN** `resolveSession()` returns `null` AND emits `AUTH_BEARER_STATIC_UNKNOWN_TOKEN` on 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.peerCertificate` is undefined - **THEN** `resolveSession()` returns `null` AND emits `AUTH_BEARER_STATIC_MTLS_REQUIRED` #### Scenario: mTLS-gated token accepts requests with peer cert - **WHEN** the same token is presented AND `request.tls.peerCertificate` is 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 real `MessageChannel` - **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 `SuaveplanError` with code `AUTH_BEARER_STATIC_INVALID_OPTIONS` is thrown synchronously **Verified by:** `src/options/bearer-static-resolver-options.test.ts::"throws on empty tokens array"`