4.8 KiB
@suaveplan/api-auth-provider — abstract account-lifecycle contract
Package: @suaveplan/api-auth-provider
Status: PROPOSED
Type: new-package
Stage: 1 (Contracts) — see umbrella openspec/changes/api-plugin-foundation/
Why
Account lifecycle (register, login, logout, refresh, oauth/*, verify-email, ...) is the second half of the auth split (design §2.3). It is OPTIONAL — sites using hosted IdPs (Clerk, Auth0, Cognito) don't need a provider; they only need a session resolver. Sites running their own auth pick one provider: Better-Auth (api-auth-better-auth, Stage 6) or the rolled-our-own reference (api-auth-rolled, Stage 8). This package owns the abstract contract: the route surface a provider owns, the path-ownership declaration (default /auth/*, configurable), and the collision detection that runs at install time so plugin routes can't accidentally squat on auth paths.
Per design §2.3: "Each provider adapter declares which paths it owns (default /auth/*, configurable). Host reserves the prefix and refuses plugin routes that collide."
What changes
Net-new package. Contract types + the route-collision detector + the conformance harness.
- ADDED:
./provider— abstractAuthProviderAdapter:pathPrefix: string(default/auth),routes(router, ctx)callback registering provider routes,lifecycle: { install, start, stop, uninstall }hooks. - ADDED:
./route-surface— declarativeProviderRouteSurface: the canonical set of paths a provider OWNS (/register,/login,/logout,/refresh,/oauth/:provider/start,/oauth/:provider/callback,/verify-email/:token,/forgot-password,/reset-password). Concrete providers MAY implement a subset; manifest declares which. - ADDED:
./path-ownership—PathOwnershipshape:{ prefix: string, owned: readonly string[] }; runtime registry tracking which paths are reserved by an installed provider. - ADDED:
./collision-detector—detectAuthPathCollisions({ provider, plugins }): CollisionReport; runs at install time. Plugin routes whose prefix overlaps withprovider.pathPrefixAND aren'tpublicRoutesMUST be reported asAUTH_PROVIDER.PATH_COLLISION. - ADDED:
./capability-id— adds"auth.provider"to theCapabilityIdunion. - ADDED:
./error-codes— frozenAUTH_PROVIDER_CODES:PATH_COLLISION,MULTIPLE_PROVIDERS_REGISTERED,PROVIDER_LIFECYCLE_FAILED,OAUTH_CALLBACK_INVALID_STATE. - ADDED:
./testing—runAuthProviderConformance(factory)reusable harness.
CapabilityId additions
This package contributes "auth.provider" to the CapabilityId union — separate from "auth.session" so a plugin can require session resolution without forcing the host to ship account-lifecycle routes.
Out of scope
- Concrete providers —
api-auth-better-auth(Stage 6),api-auth-rolled(Stage 8). - The
Principalshape or session resolution — that'sapi-auth+api-types. - OAuth state-store implementation — provider-specific.
Source mapping
Genesis-original. Source of design intent: docs/superpowers/specs/2026-05-13-api-plugin-foundation-design.md.
| Requirement | Design doc section |
|---|---|
Path ownership (/auth/*, configurable) |
§2.3 (lines 192-198) |
| Collision detection at install | §2.3 ("Host reserves the prefix and refuses plugin routes that collide") |
| Provider lifecycle hooks | §4 (FSM inherited from generic plugin lifecycle) |
| Provider route surface (register/login/oauth/verify-email) | §2.3 (lines 193-194) |
Requirements with no source line
| Requirement | Justification |
|---|---|
MULTIPLE_PROVIDERS_REGISTERED enforcement |
Implicit in §2.3 ("Mix-and-match" describes a single provider + session resolvers chain). Pinned here so the host's behavior is explicit. |
runAuthProviderConformance harness |
Stage-5 deliverable (§13.4). |
Verification approach
src/provider/provider.spec-conformance.test.ts— interface shape.src/route-surface/route-surface.test.ts— canonical path set documented; providers can declare a subset.src/collision-detector/collision-detector.test.ts— overlap rules:/auth/registercollides with plugin route/auth/x;/auth/registerdoes NOT collide with plugin route/billing/x; configurable prefix/myauthshifts the collision domain.src/path-ownership/path-ownership.test.ts— registry rejects double-registration (MULTIPLE_PROVIDERS_REGISTERED).src/capability-id/capability-id.spec-conformance.test.ts—"auth.provider"inCapabilityId.tests/dep-graph.test.ts— deps:@suaveplan/api-types,@suaveplan/api-router(peer, forRoutertype),@suaveplan/error,@suaveplan/types,zod.
Migration impact
None — additive only.
Impact
Affected dependents
- (none) — [x] no action needed (reason: net-new; concrete providers land Stages 6/8)