restructure tasks
This commit is contained in:
112
tasks/shieldai-unified-restructure/11-trpc-auth-context.md
Normal file
112
tasks/shieldai-unified-restructure/11-trpc-auth-context.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# 11. tRPC Foundation — Auth Context, Middleware, and Protected Procedures
|
||||
|
||||
meta:
|
||||
id: shieldai-unified-restructure-11
|
||||
feature: shieldai-unified-restructure
|
||||
priority: P0
|
||||
depends_on: [shieldai-unified-restructure-10]
|
||||
tags: [backend, trpc, auth, api]
|
||||
|
||||
objective:
|
||||
- Establish the tRPC foundation in the unified monolith: router factory, context builder with auth, middleware for protected routes, and error handling. Replace the stub tRPC setup with a production-ready auth-aware API layer.
|
||||
|
||||
deliverables:
|
||||
- `web/src/server/api/utils.ts` — tRPC initialization and helpers:
|
||||
- `t` object from `initTRPC.context<typeof createTRPCContext>().create()`
|
||||
- `createTRPCRouter` factory
|
||||
- `publicProcedure` — unauthenticated
|
||||
- `protectedProcedure` — requires valid JWT/session
|
||||
- `adminProcedure` — requires admin role
|
||||
- `rateLimitedProcedure` — with basic rate limiting middleware
|
||||
- `web/src/server/api/trpc.ts` — Context builder:
|
||||
- `createTRPCContext({ req, res })` that extracts auth from:
|
||||
- Session cookie (SolidStart session)
|
||||
- `Authorization: Bearer <jwt>` header
|
||||
- `x-api-key` header (for service-to-service or extension calls)
|
||||
- Returns `{ db, user, session, apiKey }` in context
|
||||
- Uses Drizzle `db` instance from `web/src/server/db/index.ts`
|
||||
- `web/src/server/api/root.ts` — Root router:
|
||||
- Imports all sub-routers
|
||||
- Exports `appRouter` and `AppRouter` type
|
||||
- `web/src/routes/api/trpc/[trpc].ts` — tRPC API handler:
|
||||
- SolidStart API route that handles all tRPC requests
|
||||
- Uses `fetchRequestHandler` from `@trpc/server/adapters/fetch`
|
||||
- Wires `createTRPCContext`
|
||||
- `web/src/lib/api.ts` — tRPC client:
|
||||
- Updates existing file to use correct `AppRouter` type
|
||||
- Adds auth token injection from localStorage/cookie
|
||||
- Handles unauthorized responses (401 → redirect to login)
|
||||
- Auth utilities:
|
||||
- `web/src/server/auth/jwt.ts` — JWT sign/verify using `jose` or `jsonwebtoken`
|
||||
- `web/src/server/auth/session.ts` — Session creation and validation
|
||||
- `web/src/server/auth/password.ts` — Password hashing with `bcrypt` or `argon2`
|
||||
|
||||
steps:
|
||||
1. Install dependencies in `web/`:
|
||||
- `@trpc/server`, `@trpc/client` (already present, verify versions match)
|
||||
- `jose` (modern JWT library, works in Edge runtime)
|
||||
- `bcryptjs` or `argon2` for password hashing
|
||||
- `zod` for input validation (already present via valibot, but standardize on one — recommend `zod` for wider ecosystem compatibility)
|
||||
2. Create `web/src/server/auth/jwt.ts`:
|
||||
- `signJWT(payload, secret, expiresIn)`
|
||||
- `verifyJWT(token, secret)`
|
||||
- Use `jose` for Edge compatibility
|
||||
3. Create `web/src/server/auth/password.ts`:
|
||||
- `hashPassword(password)` → async hash
|
||||
- `verifyPassword(password, hash)` → boolean
|
||||
4. Create `web/src/server/api/trpc.ts` (context builder):
|
||||
- Parse cookies from request headers
|
||||
- Try session cookie first (SolidStart session)
|
||||
- Fall back to Bearer JWT
|
||||
- Fall back to x-api-key
|
||||
- Look up user in database via Drizzle
|
||||
- Return context with `user`, `session`, `db`, `apiKey`
|
||||
5. Update `web/src/server/api/utils.ts`:
|
||||
- Initialize tRPC with context type
|
||||
- Define `publicProcedure`
|
||||
- Define `protectedProcedure` using middleware that checks `ctx.user` and throws `TRPCError.UNAUTHORIZED` if missing
|
||||
- Define `adminProcedure` that checks `ctx.user.role === 'admin'`
|
||||
6. Update `web/src/server/api/root.ts`:
|
||||
- Keep `exampleRouter` for now
|
||||
- Add placeholder imports for future routers
|
||||
7. Update `web/src/routes/api/trpc/[trpc].ts`:
|
||||
- Create SolidStart API route
|
||||
- Use `fetchRequestHandler` with `router: appRouter`, `createContext: createTRPCContext`
|
||||
8. Update `web/src/lib/api.ts`:
|
||||
- Import `AppRouter` from `~/server/api/root`
|
||||
- Add `httpBatchLink` with `headers` function that reads auth token from cookie/localStorage
|
||||
- Add error link that handles 401 by redirecting
|
||||
9. Test with a temporary protected route that returns `ctx.user`.
|
||||
|
||||
steps:
|
||||
- Unit: Context builder returns anonymous user for unauthenticated requests
|
||||
- Unit: Context builder returns full user for valid JWT
|
||||
- Unit: `protectedProcedure` rejects unauthenticated requests with 401
|
||||
- Unit: `adminProcedure` rejects non-admin users with 403
|
||||
- Integration: tRPC client can call public and protected endpoints
|
||||
- E2E: Login flow sets cookie/JWT and subsequent requests are authenticated
|
||||
|
||||
acceptance_criteria:
|
||||
- [ ] `createTRPCContext` correctly builds context from session, JWT, or API key
|
||||
- [ ] `publicProcedure` allows unauthenticated access
|
||||
- [ ] `protectedProcedure` requires authentication and provides `ctx.user`
|
||||
- [ ] `adminProcedure` requires admin role
|
||||
- [ ] tRPC API handler responds correctly at `/api/trpc`
|
||||
- [ ] Client library (`web/src/lib/api.ts`) connects and handles auth automatically
|
||||
- [ ] JWT sign/verify works with `jose` library
|
||||
- [ ] Password hashing uses bcrypt or argon2
|
||||
|
||||
validation:
|
||||
- Create a temporary tRPC router with public and protected queries
|
||||
- Call public query from browser → should succeed
|
||||
- Call protected query without auth → should return 401
|
||||
- Call protected query with valid JWT → should return user data
|
||||
- Run `cd web && pnpm test` to verify auth unit tests
|
||||
|
||||
notes:
|
||||
- The legacy Fastify auth middleware (`packages/api/src/middleware/auth.middleware.ts`) is the reference for auth logic. Port its JWT verification and API key handling.
|
||||
- SolidStart sessions are cookie-based. The tRPC context should read the SolidStart session cookie and validate it.
|
||||
- For the extension (task 27), API key auth will be important. Ensure `x-api-key` handling is robust.
|
||||
- Consider using `lucia-auth` or `next-auth` SolidStart integration for session management, but a custom JWT approach is fine if it matches the legacy system.
|
||||
- Standardize on `zod` for input validation across all tRPC routers. The current setup uses valibot — migrate to zod for consistency.
|
||||
- Keep auth utilities in `web/src/server/auth/` separate from tRPC to allow reuse by other server code (e.g., background jobs).
|
||||
Reference in New Issue
Block a user