94 lines
4.2 KiB
Markdown
94 lines
4.2 KiB
Markdown
# `@suaveplan/api-auth-rolled` — rolled session-token resolver (Stage 8.12 keystone)
|
|
|
|
**Package**: `@suaveplan/api-auth-rolled`
|
|
**Status**: PROPOSED
|
|
**Type**: new-package
|
|
**Stage**: 8 — see umbrella `openspec/changes/api-plugin-foundation/`
|
|
|
|
## Why
|
|
|
|
Per design doc §2.3, genesis ships two reference auth providers in v1:
|
|
Better-Auth (third-party wrapper) AND `api-auth-rolled` (composes the
|
|
genesis crypto/auth primitives end-to-end). Shipping the rolled
|
|
session-resolver in Stage 8 is the keystone that proves rotating-key
|
|
JWTs compose against the existing primitives without a third-party
|
|
dependency, and gives operators a fallback session-auth path that owns
|
|
zero third-party runtime dependencies.
|
|
|
|
This change scopes Stage 8.12 to the **session-resolver half** of the
|
|
dual contract. The matching `AuthProviderAdapter` (account-lifecycle
|
|
routes, password gating, MFA, OAuth, etc.) is deferred to a successor
|
|
change `api-auth-rolled-provider` so this milestone ships at 100%
|
|
coverage in a single iteration. Sharing the host's main DB connection,
|
|
the primitive composition, and the JWT key-rotation contract are all
|
|
established here — the successor change layers routes onto the same
|
|
adapter shape.
|
|
|
|
## What changes
|
|
|
|
- ADDED: `createRolledAuthAdapter({ store, keys, issuer, audience, ... })`
|
|
returns `AuthAdapter` (session resolver + security-scheme contribution).
|
|
- ADDED: `TokenRotator` — manages a rotating set of RS256 signing keys.
|
|
Active key signs new JWTs; retired-but-non-revoked keys still verify
|
|
in-flight tokens; revoked keys neither. `decide()` is the advisory
|
|
rotation timing signal; `setKeys()` is the operator-driven swap.
|
|
- ADDED: Session tokens are signed JWTs (RS256) via `@suaveplan/jws` +
|
|
`@suaveplan/crypto-rsa` JWKs; key rotation supported by JWKS-style key
|
|
id. The resolver accepts both `Authorization: Bearer <token>` and
|
|
`Cookie: suaveplan.session=<token>` (configurable name).
|
|
- ADDED: `RolledAuthStore` — the structural storage interface the
|
|
adapter consumes. Concrete DB-backed implementations are out of scope
|
|
for this change (operator wires them).
|
|
- ADDED: `projectUserRowToPrincipal` — maps internal `UserRow` shape to
|
|
the `@suaveplan/api-types` `Principal` contract.
|
|
- ADDED: `securitySchemes` contribution for `api-openapi` — cookie +
|
|
bearer schemes both contributed.
|
|
- ADDED: Error codes (`AUTH_ROLLED_*`): exhaustive 20-code registry
|
|
covering account-lifecycle, session, and infrastructure failure modes.
|
|
|
|
## Out of scope (deferred to `api-auth-rolled-provider`)
|
|
|
|
- `/auth/register`, `/auth/login`, `/auth/logout`, `/auth/refresh` route
|
|
implementations.
|
|
- Password hashing + strength + breach gating at registration time.
|
|
- MFA (TOTP, WebAuthn), SRP, OAuth flows.
|
|
- Email-verification / password-reset token issuance.
|
|
- Migrations for `users`, `user_sessions`, etc.
|
|
|
|
The session resolver shipped here verifies tokens issued by any provider
|
|
that signs to the same JWK set, so the dual contract is split clean —
|
|
operators MAY wire `api-auth-rolled` for session reads against a separate
|
|
provider (e.g. Clerk) that issues the JWTs.
|
|
|
|
## Source mapping
|
|
|
|
Genesis-original. Source of design intent:
|
|
`docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md`.
|
|
|
|
| Requirement | Design doc section |
|
|
|---|---|
|
|
| Implements `auth.session` | §2.3 |
|
|
| Shares the host's main DB connection | §2.3 |
|
|
| Composes `crypto-rsa` + `jws` primitives | §2.3 |
|
|
| Rotating-`kid` JWT signing | §2.3 |
|
|
|
|
## Verification approach
|
|
|
|
- `src/session/session.test.ts` — issue, verify (active kid, retired kid,
|
|
revoked kid), expired token rejected, cookie + bearer extraction.
|
|
- `src/token-rotator/token-rotator.test.ts` — `decide`/`setKeys`/
|
|
`snapshot`/`publicJwkFor` paths.
|
|
- `src/principal-projection/principal-projection.test.ts` — projection
|
|
invariants.
|
|
- `src/options/options.test.ts` — Zod schema + DATABASE_REQUIRED + key-set
|
|
invariants.
|
|
- `src/security-schemes/security-schemes.test.ts` — cookie + bearer
|
|
contributions validate.
|
|
- `src/composition/composition.spec-conformance.test.ts` — every
|
|
`AUTH_ROLLED_*` code is thrown by at least one production path.
|
|
|
|
## Migration impact
|
|
|
|
None — additive only. `api-host` registers this when
|
|
`host.auth.session = "rolled"`.
|