Files
skills/docs/api-stack/api/api-auth-bearer-static/src/factory/create-bearer-static-resolver.md
2026-05-29 08:20:56 +01:00

3.5 KiB

Direct factory — @suaveplan/api-auth-bearer-static

(no submodules)

Purpose

createBearerStaticResolver is the direct-surface entry point of the package. It accepts validated BearerStaticResolverOptions, builds a SessionResolver over the fixed token table, and returns a resolver implementation suitable for placing inside a SessionResolverChain from @suaveplan/api-auth. The resolver matches the documented chain semantics: an unknown token, missing header, or tripped mTLS gate all return null so the chain advances to the next entry.

The resolver is stateless beyond the disposed flag — there is no DB connection, no JWKS cache, no refresh loop. Disposal flips the flag and subsequent calls return null rather than throwing.

Features

  • Stateless per-request resolution; safe under concurrent fanout.
  • Constant-time token match via findTokenIndex.
  • Optional per-entry mTLS gate via checkMtlsGate.
  • Configurable headerName and prefix (Bearer by default).
  • Case-insensitive scheme match per RFC 7235.
  • OTel counter emission for every of the four outcomes.

Usage: Basic

import { createBearerStaticResolver } from "@suaveplan/api-auth-bearer-static";

const resolver = createBearerStaticResolver({
    tokens: [
        {
            token: "service-cron-2026",
            principal: {
                id: "svc_cron",
                scopes: ["jobs:run"],
                claims: { kind: "service" },
            },
        },
    ],
});

const req = new Request("https://api/x", {
    headers: { Authorization: "Bearer service-cron-2026" },
});
const principal = await resolver.resolve(req);
// principal.id === "svc_cron"

Usage: Advanced

import { createBearerStaticResolver } from "@suaveplan/api-auth-bearer-static";
import { SessionResolverChain } from "@suaveplan/api-auth";
import { createJwtResolver } from "@suaveplan/api-auth-jwt"; // hypothetical sibling

// Chained — service tokens checked first, JWT users fall through after.
const chain = new SessionResolverChain([
    createBearerStaticResolver({
        tokens: [
            {
                token: "admin-2026",
                principal: {
                    id: "svc_admin",
                    scopes: ["admin:*"],
                    claims: {},
                },
                mtlsRequired: true,
            },
        ],
        headerName: "X-Service-Auth",
        prefix: "Token",
    }),
    createJwtResolver({ issuer: "https://idp/..." }),
]);

const result = await chain.resolve(request);

API Reference

  • createBearerStaticResolver(options: BearerStaticResolverOptions): SessionResolver

Returned resolver:

  • resolve(request: Request): Promise<Principal | null>
  • dispose(): Promise<void> — idempotent.

Implementation Notes

extractToken accepts the header value, trims, splits on the first space, and lower-cases the scheme for the prefix comparison. Empty credentials after the prefix are rejected. The implementation reads the configured header by exact name (the Web Headers API normalises case on lookup, so Authorization and authorization both work). When the table contains the same token twice with conflicting principals, findTokenIndex returns the first index — operator misconfiguration the schema cannot prevent. TypeScript cannot narrow table[idx] to non-undefined even though findTokenIndex only ever returns -1 or a valid in-range index; a type assertion encodes that contract at the call site without adding a runtime guard the test would have to exercise.