10 KiB
10 KiB
Tasks: enterprise-auth
Change ID: enterprise-auth
Package: @suaveplan/auth
Target path: universal/auth/auth
Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/events, @suaveplan/crypto, @suaveplan/crypto-keys, @suaveplan/logger, @suaveplan/retry, @suaveplan/security-codes, @suaveplan/idempotency
1. Scaffold
- Create directory
universal/auth/auth/withsrc/,tests/,src/__benchmarks__/, and all feature subdirectories per the layout inproposal.md. - Write
package.jsonat version0.1.0with:"type": "module","sideEffects": falseexportsmap with a top-level"."barrel plus one subpath per feature module ("./adapters/auth-adapter/auth-adapter","./adapters/memory-adapter/memory-adapter","./api-keys/api-keys/api-keys","./jwt/token-lifecycle/token-lifecycle","./middleware/auth-middleware/auth-middleware","./schemas/auth.schemas","./types/auth.types")dependencies:@suaveplan/error workspace:^,@suaveplan/types workspace:^,@suaveplan/events workspace:^,@suaveplan/crypto workspace:^,@suaveplan/crypto-keys workspace:^,@suaveplan/logger workspace:^,@suaveplan/retry workspace:^,@suaveplan/security-codes workspace:^,@suaveplan/idempotency workspace:^,zod catalog:forms,@opentelemetry/api catalog:observability,tslib catalog:builddevDependencies:vitest catalog:testing,@vitest/coverage-istanbul catalog:testing,fast-check catalog:testing,mitata catalog:testing,@suaveplan/testing workspace:^
- Write
tsconfig.jsonextending@suaveplan/typescript-config/library.json. - Write
vitest.config.tsusingcreateTestConfig()from@suaveplan/testing/config(pool:forks). - Add
lint,typecheck,test,test:coverage,build,docs:check,benchscripts topackage.json.
2. Types and errors
2a. Types (src/types/auth.types.ts + src/types/auth.types.md)
- Define all public interfaces:
ApiKey,ApiKeyRequest,ApiKeyGeneration,ApiKeyValidationResult,JWTPayload,AuthenticatedJWTRequest,TokenValidationResult,UserContext,AuthenticatedRequest,PermissionCheckResult,SessionInfo,ApiKeyOptions,JWTOptions,MiddlewareOptions,ApiKeyMiddlewareOptions,MiddlewareFn. - Add genesis-only optional fields:
clock?: ClockandidGenerator?: IdGeneratoron all factory option interfaces;bus?: EventBusLikeonApiKeyOptions,JWTOptions,MiddlewareOptions. - Write
src/types/auth.types.md(≥200 words, simple + advanced examples, full API reference for every type).
2b. Error codes (src/error-codes.ts)
- Define
AuthErrorCodeunion — ten codes:AUTH_TOKEN_INVALID,AUTH_TOKEN_EXPIRED,AUTH_TOKEN_BLACKLISTED,AUTH_SESSION_NOT_FOUND,AUTH_SESSION_EXPIRED,AUTH_API_KEY_INVALID,AUTH_API_KEY_EXPIRED,AUTH_API_KEY_REVOKED,AUTH_PERMISSION_DENIED,AUTH_STORAGE_ERROR. - Define
AUTH_ERROR_METADATAwithhttpStatus,severity,retryable,userMessageKey,category,descriptionfor each code. - Export
registerAuthErrorCodes()— callsErrorCodes.registerMany(AUTH_ERROR_METADATA). Call as eager side-effect at file bottom. - Export
AuthErrorclass extendingSuaveplanError<AuthErrorCode>.
2c. Zod schemas (src/schemas/auth.schemas.ts + src/schemas/auth.schemas.md)
- Write Zod schemas:
ApiKeyRequestSchema,JWTOptionsSchema,ApiKeyOptionsSchema,MiddlewareOptionsSchema,AuthAdapterConfigSchema. - Write
src/schemas/auth.schemas.md. - Write
src/schemas/auth.schemas.test.ts— parse valid/invalid for each schema.
3. AuthAdapter interface
- Implement
AuthAdapterinterface insrc/adapters/auth-adapter/auth-adapter.tswith the full contract fromproposal.md. - Write
auth-adapter.md(≥200 words, integration guide, expected error behaviour for each method). - Write
auth-adapter.types.ts.
4. MemoryAuthAdapter
- Implement
MemoryAuthAdapterinsrc/adapters/memory-adapter/memory-adapter.ts:Map-backed storage for API keys (by hash), token blacklist (by jti + TTL), sessions (by sessionId).- TTL cleanup: expired tokens removed lazily on lookup (no setInterval at module scope).
- Accepts optional
{ clock?: Clock }constructor option for deterministic expiry checks.
- Write
memory-adapter.md. - Write
memory-adapter.test.ts— store/find/revoke API keys, blacklist tokens, create/find/delete sessions, TTL expiry with injected FakeClock, list operations. Eachithas{ timeout: 5000 }.
5. API key management
File: src/api-keys/api-keys/api-keys.ts
- Implement
createApiKey(request, options?):- Generate
rawKeyusing@suaveplan/crypto'srandomBytes(32 bytes, base58-encoded). - Compute HMAC-SHA256 of
rawKeywith a secret from options; store the hash (never the plaintext). - Accept
idGeneratorfor key ID,clockforcreatedAt. - Emit
auth:apikey:createdon optionalbus. - Instrument with
auth.apikey.createOTel span.
- Generate
- Implement
validateApiKey(rawKey, options?):- Hash the incoming key and look up via adapter; check revoked/expired status.
- Update
lastUsedAton successful validation. - Instrument with
auth.apikey.validateOTel span,auth.apikey_validate_totalcounter.
- Implement
revokeApiKey,listApiKeys,rotateApiKey,updateApiKeyPermissions,hasPermission,validateApiKeyMiddleware. - Write
api-keys.md(≥200 words, security model explanation, rotation guide). - Write
api-keys.test.ts(≤500 lines): creation/validation round-trip, revocation, rotation, expiry, permission check, middleware path. Eachithas{ timeout: 5000 }.
6. JWT token lifecycle
File: src/jwt/token-lifecycle/token-lifecycle.ts
- Implement
validateSessionToken(token, options?):- Decode and verify JWT signature using
@suaveplan/crypto-keys. - Check expiry via injectable
clock; check blacklist via adapter. - Return
TokenValidationResultwith structured error reason. - Instrument with
auth.token.verifyspan.
- Decode and verify JWT signature using
- Implement
refreshToken(refreshToken, options?):- Validate refresh token; issue new access + refresh token pair.
- Blacklist the old refresh token jti.
- Emit
auth:token:issuedevent onbus.
- Implement
revokeToken,revokeAllUserTokens,isTokenBlacklisted,getUserSessions,verifyTokenMiddleware,optionalTokenMiddleware. - Write
token-lifecycle.md(≥200 words, refresh flow diagram, blacklist strategy). - Write
token-lifecycle.test.ts(≤500 lines): issue/verify round-trip, expired token, blacklisted token, refresh flow, revoke all, middleware verify/optional paths.{ timeout: 5000 }on sync,{ timeout: 30000 }on async.
7. Permission middleware
File: src/middleware/auth-middleware/auth-middleware.ts
- Implement
getUserFromSession,checkPermission,requirePermission,requireAllPermissions,requireAnyPermission,withPermissions. checkPermissionuses exact string match and wildcard*(e.g.resource:*grants all actions on resource).- All middleware functions return framework-agnostic
MiddlewareFn; include acreateMiddlewareAdapterbridge for Hono and Node. - Instrument
auth.permission.checkhistogram (duration_ms). - Write
auth-middleware.md(≥200 words, wildcard semantics, framework adapter guide). - Write
auth-middleware.test.ts(≤500 lines): exact match, wildcard match, requireAll/requireAny combinations, denied path, session lookup failures.{ timeout: 5000 }on eachit.
8. OTel instrumentation (cross-cutting review)
- Confirm all spans, counters, and histograms listed in
proposal.md §5are wired in each module. - Add
tests/otel.test.ts: wire in-memory OTel exporter; assert counter increments for key create, key validate, token issue, token verify, session create, permission check.
9. Property-based tests (tests/property.test.ts)
Use fast-check. All test timeouts { timeout: 30000 }.
- API key round-trip: for any valid
ApiKeyRequest,createApiKeythenvalidateApiKeyreturnsvalid === true. - Blacklist monotonicity: once a
jtiis blacklisted viarevokeToken, all subsequentisTokenBlacklistedcalls returntrueregardless of adapter state mutations. - Permission check AND:
checkPermissionwithrequireAllPermissions([a, b])istrueiff both individual checks aretruefor arbitrary permission strings and user contexts. - MemoryAdapter eviction: after TTL elapses (injected FakeClock advanced),
isBlacklistedreturnsfalsefor expired entries.
10. Benchmarks (src/__benchmarks__/auth.bench.ts)
Use mitata.
createApiKey_throughput: 1 000 iterations againstMemoryAuthAdapter.validateApiKey_warm: 10 000 lookups on an adapter with 1 000 pre-populated keys.validateSessionToken_hmac: 10 000 verifications of a pre-issued token.- Document placeholder numbers in
README.mdunder## Benchmarks.
11. Docs
Per-file .md (all ≥200 words, simple + advanced examples, API reference):
src/types/auth.types.mdsrc/adapters/auth-adapter/auth-adapter.mdsrc/adapters/memory-adapter/memory-adapter.mdsrc/api-keys/api-keys/api-keys.mdsrc/jwt/token-lifecycle/token-lifecycle.mdsrc/middleware/auth-middleware/auth-middleware.mdsrc/schemas/auth.schemas.md
Root README:
- Write
universal/auth/auth/README.md: purpose, install, quick-start (API key + JWT round-trip), modules table, dependencies, API listing, benchmarks placeholder.
12. Verify and publish
- Run
bunx turbo lint --filter=@suaveplan/auth— zero errors. - Run
bunx turbo typecheck --filter=@suaveplan/auth— zero errors. - Run
bunx turbo test --filter=@suaveplan/auth— all tests pass. - Run
bunx turbo test:coverage --filter=@suaveplan/auth— 100/100/100/100. - Run
bun run docs:check --filter=@suaveplan/auth— zero errors. - Confirm no
TODO,FIXME,@deprecated, untypedany,ts-ignore, or.skipinsrc/ortests/. - Confirm
"sideEffects": falseinpackage.json. - Run
bun scripts/publish.ts --package @suaveplan/auth. - Update
CLAUDE.mdpackage listing to include@suaveplan/auth. - Archive: move
openspec/changes/enterprise-auth/toopenspec/archive/2026-04-24-enterprise-auth/and fold spec delta intoopenspec/specs/auth/spec.md.