Shop Flow implements JWT-based authentication with refresh tokens for enhanced security. The system uses role-based access control (RBAC) for authorization.
-
User Registration/Login
- User submits credentials to
/auth/signupor/auth/login AuthControllerreceives request and delegates toAuthServiceAuthServicevalidates credentials usingUserRepository- For login: bcrypt compares password with stored hash
- If valid, user document is returned to controller
- User submits credentials to
-
Token Generation
createSendTokenAndResponse()utility is called with user data- Two JWT tokens are generated:
- Access Token: Contains user ID, expires in 15 minutes
- Refresh Token: Contains user ID, expires in 7 days
- Both tokens are signed with different secrets
-
Token Storage
- Access token stored in:
jwtcookie (httpOnly, secure)x-auth-tokenresponse header
- Refresh token stored in:
refreshTokencookie (httpOnly, secure)- User document in database with expiration timestamp
- Access token stored in:
-
Request Authentication
- Client sends requests with access token in header or cookie
protectmiddleware intercepts all protected routes- Token extracted from
Authorization: Bearer TOKENorjwtcookie verifyToken()validates signature and expiration- User fetched from database using token's user ID
- Additional validations:
- User exists and is active
- Password wasn't changed after token issuance
- User object attached to
req.userfor downstream use
-
Authorization Check
restrictTo()middleware checks user role against allowed roles- Throws
ForbiddenErrorif user lacks required permissions - Request proceeds to route handler if authorized
-
Token Refresh Cycle
- When access token expires (15 min), client receives 401 error
- Client automatically calls
/auth/refresh-tokenwith refresh token AuthService.refreshToken()validates refresh token:- Verifies signature with refresh secret
- Checks database storage and expiration
- Ensures user is still active
- New access token generated and returned
- Process repeats until refresh token expires (7 days)
-
Logout Process
- Client calls
/auth/logout - Refresh token removed from database
- Both cookies cleared with past expiration dates
- User must re-authenticate for future requests
- Client calls
Multi-Layer Token Validation
- JWT signature verification prevents tampering
- Database lookup ensures user still exists
- Active status check prevents disabled account access
- Password change timestamp invalidates old tokens
- Refresh token database storage enables revocation
Token Separation Strategy
- Short-lived access tokens limit exposure window
- Long-lived refresh tokens reduce login frequency
- Different secrets prevent cross-token attacks
- Refresh tokens are single-use and database-validated
Password Security
- bcrypt with salt rounds prevents rainbow table attacks
- Password reset uses cryptographic tokens (SHA256)
- Reset tokens expire in 10 minutes
- Failed email sends trigger token cleanup
Request Protection
- httpOnly cookies prevent XSS token theft
- Secure flag ensures HTTPS-only transmission
- sameSite prevents CSRF attacks
- Multiple token sources provide client flexibility
- Access Token: Short-lived (15 minutes), used for API requests
- Refresh Token: Long-lived (7 days), used to generate new access tokens
{
"name": "string",
"email": "string",
"password": "string",
"passwordConfirmation": "string"
}{
"email": "string",
"password": "string"
}Clears tokens from cookies and database.
{
"email": "string"
}{
"password": "string",
"passwordConfirmation": "string"
}Uses refresh token from cookies to generate new access token.
jwt: Access token (httpOnly, secure, sameSite: strict)refreshToken: Refresh token (httpOnly, secure, sameSite: strict)
x-auth-token: Access tokenAuthorization: Bearer TOKEN: Access token
refreshToken: Hashed refresh tokenrefreshTokenExpires: Expiration timestamp
Validates access token and attaches user to request:
- Checks token from headers or cookies
- Verifies token signature
- Validates user existence and active status
- Checks password change timestamp
Restricts access based on user roles:
restrictTo("admin", "moderator");user: Default roleadmin: Administrative access
- bcrypt hashing with salt rounds
- Password change timestamp validation
- Secure password reset with crypto tokens
- Separate secrets for access/refresh tokens
- Token expiration validation
- Automatic token cleanup on logout
- Database storage for refresh token validation
- Active/inactive user status
- Account lockout for inactive users
- Email-based password recovery
JWT_SECRET=your_access_token_secret
JWT_EXPIRES_IN=15m
JWT_COOKIE_EXPIRES_IN="15 minutes"
JWT_REFRESH_SECRET=your_refresh_token_secret
JWT_REFRESH_EXPIRES_IN=7d
JWT_REFRESH_COOKIE_EXPIRES_IN="7 days"
PASSWORD_RESET_EXPIRES_IN="10m"router.get("/profile", protect, getUserProfile);router.delete("/users/:id", protect, restrictTo("admin"), deleteUser);// When access token expires (401), call refresh endpoint
fetch("/auth/refresh-token", {
method: "POST",
credentials: "include",
});NotAuthorizedError: Invalid credentials, expired tokensForbiddenError: Insufficient permissionsNotFoundError: User not foundInternalServerError: Email sending failures
- Token Rotation: Refresh tokens are single-use
- Secure Storage: Tokens stored in httpOnly cookies
- Short Lifespan: Access tokens expire quickly
- Database Validation: Refresh tokens validated against database
- Cleanup: Tokens cleared on logout