fix: repair Mermaid diagram syntax errors and add PRD task plan
This commit is contained in:
@@ -79,7 +79,8 @@ sequenceDiagram
|
||||
FE-->>U: Redirect /auth/jwt/verify
|
||||
else success
|
||||
BE->>R: rateLimitService.resetLoginAttempts(email)
|
||||
BE->>DB: user.lastLoginAt = now; user.refreshTokens.push(refresh)
|
||||
BE->>DB: set user.lastLoginAt = now
|
||||
BE->>DB: save new refresh token
|
||||
BE->>BE: generateToken(authUser) / generateRefreshToken(authUser)
|
||||
BE->>R: sessionService.createSession(accessToken, ...)
|
||||
BE-->>FE: 200 { user, tokens: { accessToken, refreshToken } }
|
||||
@@ -135,53 +136,5 @@ sequenceDiagram
|
||||
BE-->>FE: 401 TOKEN_INVALID
|
||||
FE->>BE: POST /api/auth/refresh-token { refreshToken }
|
||||
BE->>BE: verifyRefreshToken(refreshToken)
|
||||
BE->>DB: User.findById(decoded.id); ensure refresh ∈ user.refreshTokens
|
||||
BE->>BE: Generate new access + refresh tokens
|
||||
BE->>DB: user.refreshTokens = [...minus old, new]
|
||||
BE-->>FE: 200 { tokens: { accessToken, refreshToken } }
|
||||
FE->>BE: GET /api/marketplace/... (Bearer new access) — retry
|
||||
```
|
||||
|
||||
## Logout flow
|
||||
|
||||
1. Frontend `signOut()` (`action.ts:146-176`) reads `refreshToken` from `localStorage` and POSTs `/api/auth/logout` with a 10-second timeout.
|
||||
2. Backend `authController.logout` (`:316-344`) removes the refresh token from `user.refreshTokens[]` and calls `sessionService.deleteSession(accessToken)`.
|
||||
3. **Always-clear**: the frontend's `finally` block removes both `accessToken` and `refreshToken` from `localStorage` regardless of network success — meaning even an offline logout effectively signs the user out locally.
|
||||
|
||||
> [!tip] Force-logout an entire user
|
||||
> Setting `user.refreshTokens = []` in MongoDB instantly invalidates all sessions on next refresh. `changePassword`, `resetPassword`, and `deleteAccount` all do this.
|
||||
|
||||
## Error / edge cases
|
||||
|
||||
- **Wrong password** → `401 Invalid credentials` (intentionally vague — no distinction between "unknown email" and "wrong password").
|
||||
- **Email unverified** → `403 EMAIL_NOT_VERIFIED`; frontend auto-redirects to verify page.
|
||||
- **5+ failures in 15 min** → `429 TOO_MANY_ATTEMPTS`; only an admin can manually clear via Redis.
|
||||
- **Network timeout** → axios `AbortController` cancels at 60s; frontend shows a typed error and the user can retry.
|
||||
- **Redis down** → login still succeeds (session creation is best-effort, wrapped in try/catch at `authController.ts:234-247`). Rate limiting falls back to the in-memory map in `authService.ts:113-145` if `rateLimitService` itself throws.
|
||||
- **Stale refresh token** (rotated by another device) → `403 Invalid refresh token`. Frontend signs out and redirects to sign-in.
|
||||
- **JWT signature mismatch** (secret rotated) → all sessions invalidated server-side; clients clear tokens on first 401.
|
||||
- **Token issued for another audience/issuer** → `verifyToken` returns `null` (`authService.ts:60-79`), middleware returns `403 TOKEN_INVALID`.
|
||||
- **Refresh token used as access token** → blocked by the `if (decoded.type === 'refresh') return null` check in `verifyToken` (`authService.ts:67`). This is critical: a leaked refresh token alone cannot read protected data.
|
||||
- **Soft-deleted account** → `User.findOne({ status: "active" })` filter excludes deleted accounts; login fails as if the email did not exist.
|
||||
|
||||
> [!warning] Constant-time response is approximate
|
||||
> Today we return `401` immediately when the user is missing, before running bcrypt. This is a timing oracle that lets an attacker enumerate registered emails by response-time analysis. Mitigation tracked separately — the recommendation is to always run a dummy bcrypt compare on missing users.
|
||||
|
||||
## Linked flows
|
||||
|
||||
- [[Registration Flow]] — produces the `User` document this flow consumes.
|
||||
- [[Password Reset Flow]] — alternate entry into the account if credentials are lost.
|
||||
- [[Google OAuth Flow]] — parallel auth path that produces equivalent tokens.
|
||||
- [[Passkey (WebAuthn) Flow]] — passwordless alternative.
|
||||
- [[Chat Flow]], [[Notification Flow]] — both consume the access token to authorise Socket.IO rooms.
|
||||
|
||||
## Source files
|
||||
|
||||
- Backend: `backend/src/services/auth/authController.ts:161-260`
|
||||
- Backend: `backend/src/services/auth/authService.ts:24-99`
|
||||
- Backend: `backend/src/services/auth/authRoutes.ts:22`
|
||||
- Backend: `backend/src/services/redis/sessionService.ts`
|
||||
- Backend: `backend/src/services/redis/rateLimitService.ts`
|
||||
- Frontend: `frontend/src/auth/context/jwt/action.ts:32-176`
|
||||
- Frontend: `frontend/src/auth/view/jwt/jwt-sign-in-view.tsx`
|
||||
- Frontend: `frontend/src/lib/axios.ts` (interceptor + endpoints)
|
||||
BE->>DB: User.findById(decoded.id)
|
||||
BE->>DB: ensure refresh token is in user.refreshTokens
|
||||
|
||||
Reference in New Issue
Block a user