Description
Overview
The Authentication API provides comprehensive authentication and authorization functionality:
- User authentication with username/password
- Multi-factor authentication (2FA)
- JWT token management (access & refresh tokens)
- API key authentication
- CORS configuration
- Kubernetes-friendly session management
- Device tracking and security
Core Concepts
Authentication Methods
1. Bearer Token
- Access token (JWT, 15 minutes)
- Refresh token (14 days, HTTP-only cookie)
- Token rotation on refresh
- Refresh-token idle timeout policy (configurable inactivity window)
2. API Key
- Static keys from configuration
- Request header:
X-API-Key - Used for service-to-service communication
3. Application Identity (X-App-ID)
- Deterministic identifier sent via
X-App-IDheader (e.g.web-app,admin-app,configurator-app) - Scopes the refresh-token cookie per application (
refresh_token_web-app,refresh_token_admin-app, etc.) - Prevents cross-app token collisions when multiple frontends share the same domain
- Backend validates the header against a configurable whitelist (
auth.allowed_app_ids) - The App ID is stored inside the refresh token in Redis; on refresh the value must match
- When no whitelist is configured, any non-empty value is accepted (backward-compatible)
4. Multi-Factor Authentication (2FA)
- Email OTP
- Phone OTP
- TOTP (Time-based One-Time Password)
- RFC 6238 compliant
- 30-second time window
- 6-digit codes
- QR code generation for setup
- Backup codes for recovery
5. MFA Session Boundary
challenge_tokenis a pre-auth token used only for MFA/TOTP challenge flows.access_tokenis a post-auth token withsub=user_authand is the only bearer token accepted on protected routes.- For MFA-enabled users, the initial
/v1/authenticateresponse does not issue an authenticated access token or refresh-token cookie. - The authenticated session is created only after successful
/v1/verify-2FA. - Replaying
challenge_tokenon protected routes or/v1/refresh-tokenis rejected.
6. MFA mode semantics (mfa_mode)
off: After a successful password check, authentication completes without an interactive MFA step (no challenge payload); the API issues normal session artifacts (access_token, refresh cookie when applicable).email/phone/totp: Successful password verification yields a pre-auth challenge (credential_type,challenge_token, localizedmessage) until/v1/verify-2FAsucceeds.totp_setup_required: When TOTP is required but not yet enrolled, the challenge response usescredential_type: "totp_setup_required"and a localizedmessage(seeauth_m.totp_setup_requiredinauth_m.yaml). This applies in particular to Internal-role users withmfa_mode: totpand no TOTP secret yet (enrollment must finish before a full session is granted). Non-internal users intotpmode without a secret may receive the same payload when no validated email/phone fallback is available.
7. Internal invitation default MFA (users module)
Users created via /v1/users/admin/invite get their stored mfa_mode from auth.internal_invite.mfa_mode in the auth app-config module (totp, email, or phone), so privileged invites can enforce stricter MFA than the tenant default.
Security Features
Brute Force Protection
- Maximum login attempts (configurable)
- Cooling-off period
- IP-based rate limiting
- Device tracking
Admin Account Protection
- Email Alert System: Failed admin login attempts trigger immediate email notifications
- Alert Throttling: Email notifications have configurable cooldown periods to prevent spam
- Enhanced Logging: Admin access attempts include detailed metadata (IP, user agent, timestamps)
- Escalated Security: Admin accounts receive stricter security policies and monitoring
- Real-time Notifications: Security teams receive instant alerts for suspicious admin activity
Token Security
- HTTP-only cookies for refresh tokens
- Secure token rotation
- Device binding
- IP tracking
Cache Degradation (Fail-Closed)
Authentication depends on cache availability for refresh token validation and access token blacklist checks. If the cache is unavailable, auth endpoints and protected routes return 503 Service Unavailable. This prevents accepting stale access tokens when revocation cannot be enforced.
Endpoints
Authentication
Login
POST /v1/authenticate
Authenticate user and get tokens.
If the user's mfa_mode is off, the response contains the authenticated access_token and the server sets the refresh-token cookie (no MFA challenge).
If mfa_mode is email, phone, or totp (and TOTP is already enrolled where applicable), the response is a challenge response instead: no authenticated session artifacts are issued yet, and the client must complete /v1/verify-2FA first.
If TOTP is required but not enrolled, the challenge may use credential_type: "totp_setup_required" so the client can complete TOTP setup before verification.
Request Body:
{
"username": "user@example.com",
"password": "secure_password"
}Response:
{
"credential_type": "email",
"message": "OTP sent successfully",
"challenge_token": "eyJ0eXAi...",
"user_id": "123e4567-e89b-12d3-a456-426614174000"
}Admin Login
POST /v1/authenticate/admin
Authenticate admin user with Internal role and get tokens. This endpoint requires the user to have the Internal role and includes enhanced security monitoring.
When mfa_mode is not off, the initial response is a pre-auth challenge; authenticated bearer/session artifacts are issued only after /v1/verify-2FA succeeds (or after TOTP enrollment when credential_type is totp_setup_required).
Request Body:
{
"username": "admin@example.com",
"password": "secure_password"
}Response:
{
"access_token": "eyJ0eXAi...",
"expires_in": 900,
"idle_timeout_seconds": 900,
"user_id": "123e4567-e89b-12d3-a456-426614174000"
}Error Response (403):
{
"code": "auth.unauthorized_role",
"message": "User does not have the required Internal role"
}Admin Security Features:
- Enhanced Monitoring: Failed admin login attempts trigger immediate security alerts
- Email Notifications: Administrators receive real-time email alerts for suspicious activity
- Extended Cooling Periods: Admin accounts have longer lockout periods for security
- IP Tracking: All admin access attempts are logged with IP addresses and user agents
Refresh Token
POST /v1/refresh-token
Get new access token using refresh token.
The Authorization header must contain a real authenticated user_auth access token. Pre-auth challenge_token values are rejected.
Response:
{
"access_token": "eyJ0eXAi...",
"expires_in": 900,
"idle_timeout_seconds": 900,
"user_id": "123e4567-e89b-12d3-a456-426614174000"
}Verify 2FA
POST /v1/verify-2FA
Verify 2FA code and complete authentication.
This is the elevation point for MFA-enabled users. On success, the server issues the authenticated access_token and the refresh-token cookie.
When auth.2fa_challenge=true, clients must also send the challenge token returned by /v1/authenticate in X-MFA-Challenge.
Request Body:
{
"user_id": "123e4567-e89b-12d3-a456-426614174000",
"otp": "123456"
}Response:
{
"access_token": "eyJ0eXAi...",
"expires_in": 900,
"idle_timeout_seconds": 900,
"user_id": "123e4567-e89b-12d3-a456-426614174000"
}Logout
POST /v1/logout
Invalidate tokens and end session.
When the Authorization: Bearer {access_token} header is provided, the access token is immediately invalidated. Any subsequent requests using that token will return 401 Unauthorized, even if the token has not yet expired.
TOTP Management
Setup TOTP
POST /v1/totp/setup
Initialize TOTP setup for a user. Returns QR code and secret for authenticator app setup.
Request Headers:
Authorization: Bearer {challenge_token} # pre-auth TOTP setup flowUse authenticated Authorization: Bearer {access_token} only for post-login TOTP management routes such as disable/recovery operations.
Response:
{
"secret": "JBSWY3DPEHPK3PXP",
"qr_code": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"backup_codes": [
"123456789",
"987654321",
"456789123",
"789123456",
"321654987"
],
"issuer": "CoreBanq",
"account_name": "user@example.com"
}Verify TOTP Setup
POST /v1/totp/verify-setup
Verify TOTP setup by confirming the first code from authenticator app.
Request Body:
{
"secret": "JBSWY3DPEHPK3PXP",
"totp_code": "123456"
}Response:
{
"success": true,
"message": "TOTP successfully enabled"
}Verify TOTP Code
POST /v1/totp/verify
Verify TOTP code during authentication process.
Request Body:
{
"user_id": "123e4567-e89b-12d3-a456-426614174000",
"totp_code": "123456"
}Response:
{
"access_token": "eyJ0eXAi...",
"expires_in": 900,
"user_id": "123e4567-e89b-12d3-a456-426614174000"
}Verify Backup Code
POST /v1/totp/verify-backup
Verify backup code as alternative to TOTP.
Request Body:
{
"user_id": "123e4567-e89b-12d3-a456-426614174000",
"backup_code": "123456789"
}Response:
{
"access_token": "eyJ0eXAi...",
"expires_in": 900,
"user_id": "123e4567-e89b-12d3-a456-426614174000",
"remaining_codes": 4
}Disable TOTP
DELETE /v1/totp/disable
Disable TOTP for the authenticated user.
Request Headers:
Authorization: Bearer {access_token}Request Body:
{
"current_password": "user_password",
"totp_code": "123456"
}Response:
{
"success": true,
"message": "TOTP successfully disabled"
}Regenerate Backup Codes
POST /v1/totp/backup-codes/regenerate
Generate new backup codes (invalidates existing ones).
Request Headers:
Authorization: Bearer {access_token}Request Body:
{
"totp_code": "123456"
}Response:
{
"backup_codes": [
"987654321",
"123456789",
"456123789",
"789456123",
"321987654"
]
}Error Handling
All errors follow a standard format:
{
"status": 401,
"message": "Invalid credentials"
}All error responses include the X-Request-ID header for tracing:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
{"status":401,"message":"Invalid credentials"}Tip: When reporting issues, always include the X-Request-ID from the response header for faster debugging.
Error Codes
Authentication Errors
| Code | Description |
|---|---|
| auth.unauthorized | Invalid credentials |
| auth.account_locked | Account locked due to too many attempts |
| auth.unauthorized_role | User does not have the required role |
| auth.invalid_token | Invalid access token |
| auth.token_expired | Token has expired |
| auth.invalid_refresh_token | Invalid refresh token |
| auth.device_info_mismatch | Device mismatch detected |
| auth_m.invalid_app_id | X-App-ID value is not in the allowed whitelist |
| auth_m.app_id_mismatch | X-App-ID does not match the app that created the refresh token |
| auth_m.invalid_challenge | Invalid MFA challenge token |
| auth_m.challenge_already_used | MFA challenge token has already been used or expired from cache |
Admin Account Errors
| Code | Description |
|---|---|
| auth.admin_locked | Admin account locked due to failed attempts |
| auth.unauthorized_role | User does not have required Internal role |
| auth.admin_alert_sent | Security alert sent to administrators |
TOTP Errors
| Code | Description |
|---|---|
| auth.totp_invalid_code | Invalid TOTP code |
| auth.totp_code_expired | TOTP code has expired |
| auth.totp_already_enabled | TOTP is already enabled for this user |
| auth.totp_not_enabled | TOTP is not enabled for this user |
| auth.totp_setup_required | TOTP setup must be completed first |
| auth.backup_code_invalid | Invalid backup code |
| auth.backup_code_used | Backup code has already been used |
| auth.backup_codes_exhausted | All backup codes have been used |
API Key Errors
| Code | Description |
|---|---|
| auth.api_key_required | Missing API key |
| auth.invalid_api_key | Invalid API key |
Configuration
JWT Settings
auth:
jwt_secret: "your_secret_key"
access_token_ttl_minutes: 15
refresh_token_ttl_minutes: 20160 # 14 days
refresh_token_idle_timeout_minutes: 15 # inactivity timeout for refresh usageRefresh Idle Timeout Behavior
refresh_token_idle_timeout_minutesdefines the inactivity window for refresh-token usage.- If the refresh token is not used within this window, refresh validation fails and re-authentication is required.
- API token responses include
idle_timeout_secondsso clients can align UI timers with backend policy.
Cookie Settings
auth:
cookie:
# Allow insecure cookies (HTTP) for local development (default: false)
allow_insecure: false
# SameSite mode: strict, lax, or none (default: none)
# 'none' is required for cross-origin requests (e.g., frontend on separate domain/port)
same_site: "none"
# Domain for the cookie (default: empty/host-only)
# - Empty: Cookie is set for the specific host only (best for production)
# - "localhost": Auto-set when SameSite=None and host is localhost/127.0.0.1 (fixes cross-port dev)
# - Explicit Value: Set if valid for subdomains (e.g., ".example.com")
domain: ""App ID Whitelist
auth:
allowed_app_ids:
- web-app
- admin-app
- configurator-appWhen the whitelist is configured, only the listed values are accepted in the X-App-ID header. An unknown value returns 400 Bad Request.
When the list is empty or absent, any non-empty X-App-ID value is accepted (backward-compatible).
The App ID is persisted in the refresh token stored in Redis. During token refresh, the backend compares the stored App ID with the incoming X-App-ID header. A mismatch immediately revokes the token and returns 401 Unauthorized. Tokens created before this feature (no App ID stored) are not affected; the check is skipped for them.
API Key Settings
auth:
api_keys:
- "key1"
- "key2"Admin Security Settings
auth:
admin_email: "security@company.com"
brute_force:
alert:
ttl_minutes: 60 # Email notification cooldown
audit_fields_internal: true # Remove audit fields for non-internal usersCORS Settings
auth:
cors:
allowed_origins: ["https://example.com"]
allowed_methods: "GET,POST,PUT,DELETE,OPTIONS"
allowed_headers: "Content-Type,Authorization,X-API-Key"
allow_credentials: "true"TOTP Settings
auth:
totp:
issuer: "CoreBanq"
digits: 6
period: 30 # seconds
skew: 1 # allow 1 period of drift
backup_codes_count: 5
qr_code_size: 256 # pixelsSecurity Best Practices
-
Token Management
- Use short-lived access tokens
- Secure refresh token storage
- Implement token rotation
- Monitor suspicious activity
-
Device Security
- Track device information
- Detect suspicious changes
- Implement device fingerprinting
- Alert on security events
-
Rate Limiting
- Per-IP rate limits
- Cooling-off periods
- Graduated response
- Admin notifications
-
TOTP Security
- Enforce unique codes (prevent replay attacks)
- Secure secret storage
- Backup code management
- QR code security
- Time synchronization
-
Admin Account Security
- Real-time email alerts for failed login attempts
- Enhanced monitoring and logging
- Stricter cooling-off periods
- IP address and user agent tracking
- Configurable notification thresholds
Headers
Request Headers
| Header | Description |
|---|---|
| Authorization | Bearer token |
| X-API-Key | API key |
| X-Device-ID | Device identifier |
| X-App-ID | Application identifier (web-app, admin-app, configurator-app). Scopes refresh-token cookies per app. |
| X-Request-ID | Optional client-provided request ID for tracing (auto-generated if not provided) |
| Accept-Language | Preferred language |
Response Headers
| Header | Description |
|---|---|
| X-Request-ID | Unique request identifier for tracing and correlation |
| Set-Cookie | Refresh token |
Authorization on protected routes and refresh must always carry a post-auth access_token with sub=user_auth. challenge_token values are accepted only by explicit MFA/TOTP challenge handlers.
| Access-Control-Allow-* | CORS headers |
Request Tracing
All API requests include automatic request ID tracing for debugging and support purposes.
How It Works
- Client-Provided ID: If you include an
X-Request-IDheader in your request, the API will use that ID - Auto-Generated ID: If no
X-Request-IDis provided, the API automatically generates a unique UUID - Response Header: The
X-Request-IDis always returned in the response headers - Log Correlation: All server-side logs include the request ID for easy debugging
Usage Example
# With client-provided request ID
curl -X POST https://api.example.com/v1/authenticate \
-H "Content-Type: application/json" \
-H "X-Request-ID: my-custom-trace-123" \
-d '{"username": "user@example.com", "password": "password"}'
# Response headers will include:
# X-Request-ID: my-custom-trace-123# Without request ID (auto-generated)
curl -X POST https://api.example.com/v1/authenticate \
-H "Content-Type: application/json" \
-d '{"username": "user@example.com", "password": "password"}'
# Response headers will include:
# X-Request-ID: 550e8400-e29b-41d4-a716-446655440000Benefits
- Debugging: Easily trace requests through server logs
- Support: Provide the request ID when reporting issues for faster resolution
- Correlation: Track related requests across multiple API calls
- Monitoring: Use request IDs in observability tools for request tracing
Language Support
The API supports localization through the Accept-Language header:
- English (en)
- German (de)
- French (fr)
- Italian (it)
TOTP Integration Flow
Initial Setup
- User requests TOTP setup via
/v1/totp/setup - System generates secret and QR code
- User scans QR code with authenticator app
- User verifies setup with
/v1/totp/verify-setup - System enables TOTP and provides backup codes
Authentication with TOTP
- User provides username/password via
/v1/authenticate - System responds with
totp_required: true - User provides TOTP code via
/v1/totp/verify - System validates and returns access token
Backup Code Usage
- User cannot access authenticator app
- User provides backup code via
/v1/totp/verify-backup - System validates, returns token, and marks code as used
- User should regenerate backup codes
Example Integration
// Setup TOTP
const setupResponse = await fetch('/v1/totp/setup', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
});
const { secret, qr_code, backup_codes } = await setupResponse.json();
// Display QR code to user
displayQRCode(qr_code);
// Verify setup
const verifyResponse = await fetch('/v1/totp/verify-setup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: secret,
totp_code: userEnteredCode
})
});
// Store backup codes securely
storeBackupCodes(backup_codes);Admin Security Monitoring
// Example admin login with security monitoring
const adminLoginResponse = await fetch('/v1/authenticate/admin', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: 'admin@company.com',
password: adminPassword
})
});
if (!adminLoginResponse.ok) {
// Failed admin login triggers:
// 1. Enhanced logging with IP and user agent
// 2. Email notification to security team
// 3. Extended cooling-off period
// 4. Real-time alert system activation
const error = await adminLoginResponse.json();
if (error.code === 'auth.admin_locked') {
// Admin account is locked - security team has been notified
showSecurityLockoutMessage();
}
}Rate Limiting
The API implements rate limiting per IP:
- 1000 requests per minute per IP
- 100 requests per minute per endpoint
- 5 failed login attempts before cooling-off
- Admin Protection: Failed admin login attempts trigger immediate email alerts to security teams
Rate Limit Headers
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1616876520Previous Page
Authenticate user. When the user's mfa_mode is off, the response includes authenticated session artifacts and the refresh token cookie is scoped to the provided X-App-ID (e.g. refresh_token_web-app). When mfa_mode is email, phone, or totp (with TOTP enrolled), the response is a pre-auth challenge (MFAResponse) and no authenticated access token or refresh cookie is issued until /v1/verify-2FA succeeds. If mfa_mode is totp but TOTP is not enrolled—especially for Internal-role users—a challenge is returned with credential_type totp_setup_required and a localized message until enrollment completes.