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