Files
suaveplan/packages/api-stack/api/api-auth-static-principal/README.md
2026-05-27 23:29:53 +01:00

5.7 KiB

@suaveplan/api-auth-static-principal — fixed-principal session resolver for @suaveplan/api: returns a configured Principal verbatim on every request. Used in plugin integration tests and the api-plugin-example fixture.

Fixed-Principal session resolver for the @suaveplan/api plugin system. Returns the configured Principal verbatim on every request — no token decoding, no network I/O, no internal state. Used in plugin integration tests and the api-plugin-example fixture, where the goal is to exercise the entire downstream pipeline (RBAC gate, tenant resolver chain reading principal.tenantId, tenant-scoped DB) with a deterministic identity carried in config.

Documentation tree

  • adapter — Bundles the static-principal resolver, the (absent) security-scheme contribution, and a pinned csrf: false into a sin…
    • adapter — Bundles the static-principal resolver, the (absent) security-scheme contribution, and a pinned csrf: false into a sin…
  • error-codes — Defines the AUTH_STATIC_PRINCIPAL.* error-code namespace and the AuthStaticPrincipalError concrete subclass of `@su…
    • error-codes — Defines the AUTH_STATIC_PRINCIPAL.* error-code namespace and the AuthStaticPrincipalError concrete subclass of `@su…
  • factory — Constructs a SessionResolver from @suaveplan/api-auth that returns the configured Principal verbatim on every req…
  • options — Owns the runtime contract between the test harness call site and the resolver factory. The schema validates both the ou…
    • options — Owns the runtime contract between the test harness call site and the resolver factory. The schema validates both the ou…
  • security-scheme — Provides the per-adapter SecuritySchemeContribution slot of AuthAdapter. The static-principal adapter is a test-onl…
    • security-scheme — Provides the per-adapter SecuritySchemeContribution slot of AuthAdapter. The static-principal adapter is a test-onl…

Why does this exist?

Per the API foundation design doc §13.2, the testing kit needs an auth adapter that supplies a fixed Principal without any token decoding. The §13.2 example uses it directly:

adapters: {
    "auth.session": {
        kind: "static-principal",
        principal: { id: "u1", scopes: ["billing:write"], tenantId: "acme" },
    },
}

Tests exercise the whole pipeline — RBAC, tenant resolution, tenant-scoped DB — with a deterministic principal in config. No mocks, no JWKS setup, no token signing.

Surface

Subpath Export
./resolver createStaticPrincipalResolver(opts): SessionResolver
./adapter createStaticPrincipalAdapter(opts): AuthAdapter
./error-codes AUTH_STATIC_PRINCIPAL_CODES, AuthStaticPrincipalError, AuthStaticPrincipalErrorCode

The root barrel re-exports the resolver, adapter, error codes, options schema (StaticPrincipalResolverOptionsSchema / parseStaticPrincipalResolverOptions), and the empty staticPrincipalSecurityScheme() contribution.

Usage

import { createStaticPrincipalAdapter } from "@suaveplan/api-auth-static-principal/adapter";

const adapter = createStaticPrincipalAdapter({
    principal: {
        id: "u1",
        scopes: ["billing:write"],
        tenantId: "acme",
        claims: { sub: "u1" },
    },
});

host.registerAuth(adapter);
// every request now produces `principal === { id: "u1", ... }`.

Skip auth on selected paths to test publicRoutes behaviour without rewiring the adapter chain:

const adapter = createStaticPrincipalAdapter({
    principal: { id: "u1", scopes: [], claims: {} },
    nullForPaths: ["/healthz", "/webhooks/*"],
    applyTo: (req) => !req.headers.has("x-skip-auth"),
});

Conformance

The resolver passes runAuthSessionConformance from @suaveplan/api-auth/testing in seeded-principal mode. See src/factory/create-static-principal-resolver.spec-conformance.test.ts and tests/conformance/api-auth.test.ts.

Errors

AUTH_STATIC_PRINCIPAL.INVALID_OPTIONS — outer options bag failed Zod validation (wrong shape, missing required fields, unknown top-level keys).

AUTH_STATIC_PRINCIPAL.INVALID_PRINCIPAL — the supplied principal field is malformed (missing id, non-string id, non-array scopes, unknown keys inside principal, …).

Both fire synchronously at construction time. The resolver itself never throws at request time.

Stage-5 wiring (forward-looking)

When api-host/testing ships its Stage-5 createTestHost surface, this adapter is registered in the adapter table under kind: "static-principal", so tests will declare it inline:

const host = createTestHost({
    adapters: {
        "auth.session": {
            kind: "static-principal",
            principal: { id: "u1", scopes: ["billing:write"], tenantId: "acme" },
        },
    },
});

Until then, callers wire the adapter directly via createStaticPrincipalAdapter() as shown above.