first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
# Direct factory — `@suaveplan/api-auth-bearer-static`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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
```ts
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
```ts
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.