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

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 — findTokenIndex performs a constant-time lookup of a presented bearer token against a fixed table, returning the match…
    • token-match — findTokenIndex performs a constant-time lookup of a presented bearer token against a fixed table, returning the 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…
  • factory — createBearerStaticResolver is the direct-surface entry point of the package. It accepts validated `BearerStaticResolv…
    • create-bearer-static-resolver — createBearerStaticResolver is the direct-surface entry point of the package. It accepts validated `BearerStaticResolv…
  • 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…
  • security-scheme — This module builds the OpenAPI 3.1 components.securitySchemes contribution the adapter publishes to the host's `AuthA…
    • security-scheme-contribution — This module builds the OpenAPI 3.1 components.securitySchemes contribution the adapter publishes to the host's `AuthA…
  • 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 —…

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.