Login & Authentication
Endpoints for user authentication.
Admin Account
The admin account is created from environment variables when the backend starts:
| Variable | Required | Description |
|---|---|---|
ADMIN_EMAIL | Yes | Email address used to log in |
ADMIN_PASSWORD | Yes | Password for the admin account |
Behavior:
- First boot (no users): The admin account is created with the email and password from the env vars.
- Subsequent boots: If
ADMIN_EMAILorADMIN_PASSWORDchange, the existing admin account is updated to match. - No password strength rules are enforced for these env vars, so deployment platforms can accept any value you set.
Set ADMIN_EMAIL and ADMIN_PASSWORD in your backend .env (see Quickstart). After starting the backend, use those credentials to log in via the dashboard or the Login endpoint below.
Login
Authenticate an existing user.
POST /api/v1/auth/loginRequest
curl -X POST https://your-instance.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "SecurePassword123!",
"rememberMe": false
}'Request Body
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | User's email address |
password | string | Yes | User's password |
rememberMe | boolean | No | Extended refresh token (30 days vs 24h) |
Response
Success (200):
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"createdAt": "2024-01-15T10:30:00.000Z"
}
}Errors
| Status | Error | Cause |
|---|---|---|
| 400 | Email and password are required | Missing fields |
| 401 | Invalid email or password | Wrong credentials |
| 423 | Account is temporarily locked... | Too many failed attempts |
Account Lockout
After 5 failed login attempts, the account is locked for 15 minutes.
Lockout Response (423):
{
"error": "Account is temporarily locked due to too many failed login attempts",
"lockedUntil": "2024-01-15T10:45:00.000Z"
}The lockout:
- Resets automatically after 15 minutes
- Resets on successful login
- Counter resets after successful login
Get Current User
Get information about the authenticated user.
GET /api/v1/auth/meRequest
curl -X GET https://your-instance.com/api/v1/auth/me \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Response
Success (200):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"createdAt": "2024-01-15T10:30:00.000Z"
}Errors
| Status | Error | Cause |
|---|---|---|
| 401 | Authorization header required | No token |
| 401 | Invalid token | Token invalid or expired |
Logout
Logout the current user and invalidate tokens.
POST /api/v1/auth/logoutRequest
curl -X POST https://your-instance.com/api/v1/auth/logout \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}'Request Body (Optional)
| Field | Type | Required | Description |
|---|---|---|---|
refreshToken | string | No | Refresh token to explicitly revoke |
Response
Success (200):
{
"success": true,
"message": "Logged out successfully"
}What Happens on Logout
- Access token blacklisted - Immediately invalidated via Redis
- Refresh token revoked - If provided, removed from Redis
- Client should - Clear stored tokens
The access token is blacklisted for its remaining lifetime (up to 15 minutes), ensuring it cannot be reused.
Authentication Flow Example
1. Login
Use the credentials from your backend ADMIN_EMAIL and ADMIN_PASSWORD.
const response = await fetch('/api/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'user@example.com',
password: 'SecurePassword123!',
rememberMe: true
})
});
const { accessToken, refreshToken, user } = await response.json();
// Store tokens securely
storeAccessToken(accessToken);
storeRefreshToken(refreshToken);2. Make Authenticated Requests
const response = await fetch('/api/v1/agents', {
headers: {
'Authorization': `Bearer ${getAccessToken()}`
}
});3. Handle Token Expiration
// When access token expires (401 response)
const refreshResponse = await fetch('/api/v1/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
refreshToken: getRefreshToken()
})
});
if (refreshResponse.ok) {
const { accessToken, refreshToken } = await refreshResponse.json();
storeAccessToken(accessToken);
storeRefreshToken(refreshToken);
// Retry original request
} else {
// Redirect to login
redirectToLogin();
}4. Logout
await fetch('/api/v1/auth/logout', {
method: 'POST',
headers: {
'Authorization': `Bearer ${getAccessToken()}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
refreshToken: getRefreshToken()
})
});
// Clear stored tokens
clearTokens();