Authentication API Endpoints
Express + PostgreSQL + Prisma Backend
This document describes all authentication endpoints exposed by the backend API.
The authentication system uses:
- JWT access tokens
- Refresh tokens stored in HttpOnly cookies
- Role-based authorization
The frontend (Next.js) is a pure HTTP client and does not manage sessions.
Base Path
All authentication routes are under:
/api/authExample:
POST /api/auth/loginAuthentication Model
| Component | Purpose |
|---|---|
| Access Token (JWT) | Used to access protected API endpoints |
| Refresh Token | Used to obtain a new access token |
| HttpOnly Cookie | Stores refresh token securely |
| Authorization Header | Carries the JWT access token |
Protected endpoints require:
Authorization: Bearer <access_token>1. Login
Authenticate a user and issue tokens.
POST /api/auth/login
```text
**Request Body**
```json
{
"email": "admin@example.com",
"password": "StrongPassword123!"
}Response
{
"accessToken": "<jwt_token>",
"user": {
"id": "uuid",
"email": "admin@example.com",
"name": "Admin",
"role": "ADMIN"
}
}Cookie Set
refresh_token
Cookie properties:
Property Value HttpOnly true Path /api/auth SameSite Strict Secure true in production
2. Refresh Access Token
Issue a new access token using the refresh token cookie.
POST /api/auth/refreshRequest
No body required.
The refresh token cookie is automatically sent by the browser.
Example:
Cookie: refresh_token=<token>Response
{
"accessToken": "<new_jwt_token>"
}3. Logout
Invalidate the refresh token and clear the cookie.
POST /api/auth/logoutRequest
No body required.
The refresh token cookie must be present.
Response
{
"message": "Logged out successfully"
}Effect
The server:
- Invalidates the refresh token
- Clears the cookie
4. Current User
Retrieve the authenticated user’s information.
GET /api/auth/meHeaders
Authorization: Bearer <access_token>Response
{
"id": "uuid",
"email": "admin@example.com",
"name": "Admin",
"role": "ADMIN"
}5. Bootstrap First Admin
Create the first admin account when the system has no users.
POST /api/auth/bootstrapThis endpoint is available only when:
NODE_ENV != productionor
ALLOW_BOOTSTRAP=trueRequest Body
{
"email": "admin@example.com",
"password": "StrongPassword123!",
"name": "System Administrator"
}Response
{
"message": "Admin user created successfully"
}If an admin already exists:
409 ConflictError Responses
Typical authentication errors.
Invalid Credentials
401 Unauthorized
```text
```json
{
"error": "Invalid email or password"
}Missing Token
401 Unauthorized{
"error": "Access token required"
}Invalid Token
401 Unauthorized{
"error": "Invalid or expired token"
}Frontend Usage (Next.js)
Example login request:
const res = await fetch("/api/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
credentials: "include",
body: JSON.stringify({
email,
password
})
});Protected request example:
const res = await fetch("/api/orders", {
headers: {
Authorization: `Bearer ${accessToken}`
}
});Refresh token example:
await fetch("/api/auth/refresh", {
method: "POST",
credentials: "include"
});Recommended Token Lifetimes
Token Lifetime Access Token 15 minutes Refresh Token 7 days
Example .env configuration:
JWT_ACCESS_TTL=15m
JWT_REFRESH_TTL=7dSecurity Recommendations
Always follow these practices:
Use HTTPS in production
Required for secure cookies.
Keep JWT secrets private
Store only in environment variables.
Use short-lived access tokens
Limits damage if compromised.
Validate roles on the server
Never trust frontend authorization logic.
Protect refresh tokens
Always store them in HttpOnly cookies.
Summary
Authentication flow:
- User logs in
- Server returns JWT access token
- Refresh token stored as HttpOnly cookie
- Client calls protected endpoints using Authorization header
- When access token expires, client calls /api/auth/refresh
The Express backend remains the single source of truth for authentication and authorization.