Appearance
Auth JWT Migration
Purpose: Replace cookie-based sessions with JWT so mobile clients can authenticate without a browser.
Done when:
- All 14 route guards accept JWT bearer tokens
- Refresh token rotation is implemented at POST /auth/refresh
- Cookie-based session middleware is removed
- Integration tests pass for both access and refresh token flows
Status: In Progress
Progress: ~60%
Plan
- [x] Design token schema and choose signing algorithm (RS256)
- [x] Implement JWT issuing at POST /auth/login
- [x] Add token verification middleware
- [x] Implement refresh token rotation at POST /auth/refresh
- [ ] Update route guards to accept JWT (8 of 14 done)
- [ ] Remove old session middleware
- [ ] Write integration tests for token flows
- [ ] Update API documentation
Session Log
Session 3 — 2026-03-17
What happened:
- Implemented refresh token rotation at POST /auth/refresh
- Decided to use Redis for refresh token storage instead of Postgres — the token-revocation lookup needs to be fast at scale and Redis TTL handles expiry automatically
- Updated 8 of 14 route guards to accept JWT bearer tokens
- Discovered that the admin routes use a different auth pattern (role-based middleware) — these need special handling
Blocked on: Nothing
Next: Update the remaining 6 route guards. The admin routes (src/routes/admin/*.js) use requireRole() middleware that reads from req.session — refactor it to read from req.user (set by the new JWT middleware) instead. After that, remove the old session middleware and write integration tests.
Session 2 — 2026-03-15
What happened:
- Implemented JWT issuing at POST /auth/login
- Added token verification middleware at src/middleware/auth.js
- Tried using HS256 initially but switched to RS256 — the API gateway needs to verify tokens without access to the signing secret
- Set access token TTL to 15 minutes, refresh token to 7 days
Blocked on: Nothing
Next: Implement refresh token rotation at POST /auth/refresh. Use Redis for token storage (see decision above about RS256). Then start updating route guards — there are 14 total, listed in src/routes/index.js.
Session 1 — 2026-03-14
What happened:
- Created workstream from issue #42
- Designed token schema: access token carries user ID, email, and roles; refresh token is opaque and stored server-side
- Chose RS256 for signing so the API gateway can verify without the private key
- Sketched out the migration plan in the checklist above
Blocked on: Nothing
Next: Implement JWT issuing at POST /auth/login — start with src/routes/auth.js and add a new issueTokenPair() utility.