POST /api/auth/loginDescription: Authenticate a user and receive a JWT token for accessing protected endpoints.
Request Body:
{
"username": "admin",
"password": "admin"
}Response (200 — success):
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"username": "admin",
"role_id": 1,
"role_name": "admin",
"is_system_role": true,
"permissions": [
"users:list",
"users:create",
"users:update",
"users:delete",
"users:read",
"scraper:trigger",
"scraper:trigger_single",
"theaters:create",
"theaters:update",
"theaters:delete",
"theaters:read",
"settings:read",
"settings:update",
"settings:reset",
"settings:export",
"settings:import",
"reports:list",
"reports:view",
"system:info",
"system:health",
"system:migrations",
"roles:list",
"roles:read",
"roles:create",
"roles:update",
"roles:delete"
]
}
}
}Response (401 — invalid credentials):
{
"success": false,
"error": "Invalid credentials"
}Response (400 — missing fields):
{
"success": false,
"error": "Username and password are required"
}Example:
# Login and save token
TOKEN=$(curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' | jq -r '.data.token')
# Use token for protected endpoints
curl http://localhost:3000/api/reports \
-H "Authorization: Bearer $TOKEN"Note: The default admin account is created automatically on first database initialization with username admin and password admin. Change this password in production.
POST /api/auth/registerAuthentication: Required (Bearer token)
Role: Admin only
Description: Create a new user account. Only administrators can register new users.
Request Body:
{
"username": "newuser",
"password": "securepassword"
}Response (201 — created):
{
"success": true,
"data": {
"message": "User registered successfully",
"user": {
"id": 2,
"username": "newuser",
"role": "user"
}
}
}Response (409 — username exists):
{
"success": false,
"error": "Username already exists"
}Response (401 — unauthorized):
{
"success": false,
"error": "Unauthorized"
}Response (403 — not admin):
{
"success": false,
"error": "Admin access required"
}Example:
# Get admin token first
TOKEN=$(curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' | jq -r '.data.token')
# Register new user (admin only)
curl -X POST http://localhost:3000/api/auth/register \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"username":"newuser","password":"securepass123"}'POST /api/auth/change-passwordAuthentication: Required (Bearer token)
Description: Change the password for the currently authenticated user. Requires the current password for verification.
Request Body:
{
"currentPassword": "current_password",
"newPassword": "new_secure_password"
}Response (200 — success):
{
"success": true,
"data": {
"message": "Password changed successfully"
}
}Response (401 — invalid current password):
{
"success": false,
"error": "Current password is incorrect"
}Response (400 — missing fields):
{
"success": false,
"error": "Current password and new password are required"
}Response (401 — unauthorized, no token):
{
"success": false,
"error": "Unauthorized"
}Example:
# Get auth token first
TOKEN=$(curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin"}' | jq -r '.data.token')
# Change password
curl -X POST http://localhost:3000/api/auth/change-password \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"currentPassword":"admin","newPassword":"NewSecurePass123!"}'
# Verify new password works (should succeed)
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"NewSecurePass123!"}'Security Notes:
- Requires valid JWT token (must be logged in)
- Current password must be provided (prevents unauthorized password changes if session is hijacked)
- Failed password change attempts count toward rate limiting
- Password is hashed with bcrypt before storage (never stored in plaintext)
All JWT tokens issued by the /api/auth/login endpoint have a configurable expiration time:
- Default: 1 hour from issue time
- Configuration: Set via
JWT_EXPIRES_INenvironment variable - Format: Any valid
jsonwebtokenduration string (e.g.,1h,7d,30m) - Algorithm: HS256 (HMAC with SHA-256)
- No Refresh Tokens: Users must re-login after expiry
Example Configuration:
JWT_EXPIRES_IN=1h # Default: 1 hour
JWT_EXPIRES_IN=7d # Alternative: 7 days
JWT_EXPIRES_IN=30m # Alternative: 30 minutesThe React client implements proactive token expiry handling:
- At Login: Client decodes JWT to extract
exp(expiry timestamp) - Timer Set:
setTimeoutscheduled to fire exactly when token expires - Auto-Logout: When timer fires, user is automatically logged out
- User Feedback: Login page shows "Votre session a expiré. Veuillez vous reconnecter."
- No Surprise Errors: Users never encounter 401 errors from expired tokens
Benefits:
- Seamless UX with clear session expiry messaging
- No failed API requests due to expired tokens
- Consistent behavior across all browser tabs (via localStorage events)
All protected endpoints validate JWT tokens:
401 Response on Expired Token:
{
"success": false,
"error": "Unauthorized"
}Note: In practice, users rarely see this error because the client proactively logs them out before tokens expire. This 401 response typically only occurs if:
- User manually manipulates localStorage
- System clock skew between client and server
- User has multiple tabs with different token states
Important: Permissions are baked into the JWT at login time. If a user's role or permissions change:
- Changes do NOT take effect until user re-logs in
- Old token remains valid with old permissions until expiry
- User must logout and login again to receive updated permissions in new JWT
Example Scenario:
1. User logs in as 'operator' → JWT contains 9 operator permissions
2. Admin promotes user to 'admin' role (26 permissions)
3. User still has 9 permissions until they re-login
4. User must logout and login to receive new JWT with 26 admin permissions
See Roles and Permissions Reference for complete RBAC documentation.
Last updated: March 15, 2026