Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.3 KiB
@suaveplan/api-auth-bearer-static — SessionResolver adapter for service-to-service static bearer tokens. Matches Authorization: Bearer against a fixed token→Principal table using constant-time comparison from @suaveplan/crypto-utils; unknown tokens defer to the next chain entry. Supports an optional per-token mutual-TLS gate that rejects when the host did not surface request.tls.peerCertificate. Ships both a direct surface (createBearerStaticResolver) and a worker-proxy surface (createBearerStaticResolverWorkerProxy) over @suaveplan/api-worker-rpc; both pass runAuthSessionConformance from @suaveplan/api-auth/testing. OpenAPI security-scheme contribution (HTTP Bearer). Zod-validated options, AUTH_BEARER_STATIC.* error codes, OTel match counter partitioned by outcome.
Stage-4 service-to-service SessionResolver adapter for the
@suaveplan/api plugin system. Matches an inbound Authorization: Bearer <token> header against a fixed token → Principal table using
constant-time comparison from @suaveplan/crypto-utils. Unknown tokens
return null so the host's SessionResolverChain falls through to the
next adapter (typically api-auth-jwt for user sessions).
Ships both the direct surface (createBearerStaticResolver) and the
worker-proxy surface (createBearerStaticResolverWorkerProxy +
serveBearerStaticResolverOnPort) over @suaveplan/api-worker-rpc; both
pass runAuthSessionConformance from @suaveplan/api-auth/testing.
Documentation tree
- constant-time —
findTokenIndexperforms a constant-time lookup of a presented bearer token against a fixed table, returning the match…- token-match —
findTokenIndexperforms a constant-time lookup of a presented bearer token against a fixed table, returning the match…
- token-match —
- error-codes — The error-codes module defines the stable
AUTH_BEARER_STATIC.*namespace that every public failure path in this packa…- error-codes — The error-codes module defines the stable
AUTH_BEARER_STATIC.*namespace that every public failure path in this packa…
- error-codes — The error-codes module defines the stable
- factory —
createBearerStaticResolveris the direct-surface entry point of the package. It accepts validated `BearerStaticResolv…- create-bearer-static-resolver —
createBearerStaticResolveris the direct-surface entry point of the package. It accepts validated `BearerStaticResolv…
- create-bearer-static-resolver —
- mtls — The mTLS gate enforces an optional second factor on individual token table entries. When operators mark an entry with `…
- mtls-gate — The mTLS gate enforces an optional second factor on individual token table entries. When operators mark an entry with `…
- options — The options module owns the public construction surface of every resolver in this package. It defines the `BearerStatic…
- bearer-static-resolver-options — The options module owns the public construction surface of every resolver in this package. It defines the `BearerStatic…
- proxy — The worker-proxy surface is the second of the two Stage-4 surfaces this adapter ships (
§5.2a). It lets the host insta…- create-bearer-static-resolver-worker-proxy — The worker-proxy surface is the second of the two Stage-4 surfaces this adapter ships (
§5.2a). It lets the host insta…
- create-bearer-static-resolver-worker-proxy — The worker-proxy surface is the second of the two Stage-4 surfaces this adapter ships (
- security-scheme — This module builds the OpenAPI 3.1
components.securitySchemescontribution the adapter publishes to the host's `AuthA…- security-scheme-contribution — This module builds the OpenAPI 3.1
components.securitySchemescontribution the adapter publishes to the host's `AuthA…
- security-scheme-contribution — This module builds the OpenAPI 3.1
- telemetry — The telemetry module owns the single OpenTelemetry counter this package emits —
api.auth.bearer_static_match_total—…- instruments — The telemetry module owns the single OpenTelemetry counter this package emits —
api.auth.bearer_static_match_total—…
- instruments — The telemetry module owns the single OpenTelemetry counter this package emits —
Install
bun add @suaveplan/api-auth-bearer-static
Direct surface
import { createBearerStaticResolver } from "@suaveplan/api-auth-bearer-static";
import { SessionResolverChain } from "@suaveplan/api-auth";
const serviceAuth = createBearerStaticResolver({
tokens: [
{
token: process.env.CRON_TOKEN,
principal: {
id: "svc_cron",
scopes: ["jobs:run"],
claims: { kind: "service" },
},
},
{
token: process.env.ADMIN_TOKEN,
principal: {
id: "svc_admin",
scopes: ["admin:*"],
claims: { kind: "admin" },
},
mtlsRequired: true,
},
],
});
// Chained — service tokens first, JWT users fall through.
const chain = new SessionResolverChain([serviceAuth, jwtResolver]);
Chained-resolver pattern with api-auth-jwt
The intended deployment topology pairs this adapter with
@suaveplan/api-auth-jwt for user sessions. Static-token callers match
first; everything else flows to JWT. The chain's first-match-wins
semantics means unknown tokens never throw — they simply move on.
import { SessionResolverChain } from "@suaveplan/api-auth";
import { createBearerStaticResolver } from "@suaveplan/api-auth-bearer-static";
import { createJwtSessionResolver } from "@suaveplan/api-auth-jwt"; // future sibling
const chain = new SessionResolverChain([
createBearerStaticResolver({
tokens: [/* service callers */],
}),
createJwtSessionResolver({
issuer: "https://idp.example",
audience: "suaveplan",
}),
]);
Worker-proxy surface
Use the worker-proxy variant when the host process should not hold the
real token table — e.g. an isolated auth worker serving multiple host
workers. The host imports createBearerStaticResolverWorkerProxy(port);
the worker imports serveBearerStaticResolverOnPort(port, options). The
proxy transparently passes runAuthSessionConformance, so plugin code
treats it identically to the direct surface.
// host.ts
const proxy = createBearerStaticResolverWorkerProxy(port);
const chain = new SessionResolverChain([proxy, jwtResolver]);
// worker.ts
serveBearerStaticResolverOnPort(port, {
tokens: [/* real table — never crosses to the host */],
});
Optional mutual-TLS gate
Token entries MAY carry mtlsRequired: true. When set, the resolver
requires the host listener to surface a verified peer certificate via
request.tls.peerCertificate; absent → returns null (outcome:
mtls-required). The adapter does NOT establish TLS — that is the host
listener's responsibility (Bun TLS, Node https, Cloudflare Worker TLS
terminator, etc.).
Token rotation
This adapter is intentionally static — rotate tokens by reloading host
config. There is no DB-backed lookup, no JWKS, no refresh loop. If
you need rotation without restarts, use api-auth-better-auth or a
future api-auth-token-table adapter; this one is the simplest possible
thing that resolves a fixed table against constant-time match.
Errors
The package exposes the AUTH_BEARER_STATIC.* code namespace via
AUTH_BEARER_STATIC_CODES. Only INVALID_OPTIONS is thrown
(synchronously, at factory construction); NO_TOKEN, UNKNOWN_TOKEN,
and MTLS_REQUIRED are surfaced via the OTel match counter's outcome
label.
Telemetry
One counter — api.auth.bearer_static_match_total{outcome=match|no-token|unknown-token|mtls-required}
— increments exactly once per resolve() call.
Conformance
Both surfaces pass runAuthSessionConformance from
@suaveplan/api-auth. Spec-conformance tests live alongside the source
under src/factory/*.spec-conformance.test.ts and
src/proxy/*.spec-conformance.test.ts.