Pro Login and Session Management
Summary
This process covers the full session lifecycle for a Pro: logging in with email/password, silently refreshing the access token via the httpOnly cookie, and logging out. Refresh tokens are rotated on every use (one active token per device type). Deactivated accounts are blocked at login.
State Diagram
stateDiagram-v2 state "Déconnecté" as LoggedOut state "Authentification en cours" as Authenticating state "Compte bloqué" as Blocked state "Session active" as Active state "Renouvellement session" as Refreshing [*] --> LoggedOut LoggedOut --> Authenticating: pro submits credentials Authenticating --> Blocked: isActive = false Authenticating --> Active: credentials valid Active --> Refreshing: access token expires, pro refreshes session Refreshing --> Active: valid cookie → new token pair issued Refreshing --> LoggedOut: token expired or superseded Active --> LoggedOut: pro logs out Blocked --> [*]
Steps
1. Login (Actor: pro)
Pro sends POST /pro/auth/login with email (normalised to lowercase) and password. Rate limited to 10 requests per minute.
The system looks up the Pro by email, verifies the password hash, then checks isActive. If the account is deactivated, returns 403 immediately.
Any existing ProRefreshToken for the same deviceType (parsed from User-Agent header: "web" or "mobile") is deleted before issuing a new one. This enforces a maximum of one active session per device type.
Triggers: Pro submits login form
Outcome: Access token in response body; refresh token as httpOnly cookie proRefreshToken (7-day maxAge)
2. Authenticated Requests (Actor: pro)
The client sends Authorization: Bearer <accessToken> on every API request. The authenticatePro hook verifies the JWT using PRO_JWT_SECRET, then performs a DB lookup on the Pro to check isActive and enforce the CNI gate (see cni-upload-analysis).
Triggers: Any protected route call
Outcome: request.proId set; request proceeds or 401/403 returned
3. Token Refresh (Actor: system)
When the 15-min access token expires, the client sends POST /pro/auth/refresh. The server reads the proRefreshToken cookie, hashes it with SHA-256, and looks up the ProRefreshToken row.
- If not found → 401
SESSION_EXPIRED/SESSION_SUPERSEDED - If found but expired → 401
SESSION_EXPIRED/TOKEN_EXPIRED - If the Pro is inactive → deletes the token, returns 401
On success: the old ProRefreshToken row is deleted and a new one is created (rotation). A new access token and a new refresh cookie are returned.
Triggers: Client detects expired access token and retries Outcome: New token pair; old refresh token invalidated
4. Logout (Actor: pro)
POST /pro/auth/logout. The server reads the cookie, hashes it, and deletes matching ProRefreshToken rows. The cookie is cleared by setting maxAge: 0. No auth required — the endpoint is always accessible (cookie may already be absent).
Triggers: Pro clicks “Se déconnecter” Outcome: Session terminated; cookie cleared
Error States
- Invalid credentials → 401
UNAUTHORIZED - Deactivated account (login) → 403
ACCOUNT_DISABLED— “Votre compte a été désactivé. Contactez support@sealion.fr” - Deactivated account (refresh) → 401
UNAUTHORIZED— “Account unavailable”; refresh token deleted - No refresh cookie → 401
UNAUTHORIZED— “No refresh token” - Token not found in DB → 401
SESSION_EXPIRED/SESSION_SUPERSEDED - Token expired → 401
SESSION_EXPIRED/TOKEN_EXPIRED
Related Processes
- registration — account must exist before login
- cni-upload-analysis — CNI gate checked on every authenticated request
- account-deactivation — sets
isActive: false, immediately blocks login