Secure Storage
Store tokens in HttpOnly cookies or secure storage, never in plain localStorage for production.
The Quantum Trader API uses JWT (JSON Web Tokens) for authentication. Access tokens expire after 30 minutes, refresh tokens after 30 days.
┌─────────┐ ┌─────────┐ ┌─────────┐│ Login │ ──► │ Tokens │ ──► │ API ││ POST │ │ Stored │ │ Calls │└─────────┘ └─────────┘ └─────────┘ │ ▼ ┌─────────────┐ │ Refresh │ (when access token expires) │ Tokens │ └─────────────┘| Method | Endpoint | Auth Required | Description |
|---|---|---|---|
POST | /auth/login | No | Login and get tokens |
POST | /auth/refresh | No | Refresh access token |
POST | /auth/logout | Yes | Revoke refresh token |
GET | /auth/me | Yes | Get current user info |
Authenticate with username/email and password to receive JWT tokens.
POST /api/v1/auth/loginContent-Type: application/json
{ "password": "your_password"}{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJjOTZjYTNlNS05NGExLTQ5ZTMtYjk2NS0zZTMyZmZiNThiODMiLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE3NjU5MTQxMjl9...", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer"}| Field | Type | Required | Description |
|---|---|---|---|
username | string | Yes | Username or email address |
password | string | Yes | Account password |
| Field | Type | Description |
|---|---|---|
access_token | string | JWT for API authentication (30 min expiry) |
refresh_token | string | JWT for refreshing access token (30 day expiry) |
token_type | string | Always "bearer" |
| Status | Cause | Response |
|---|---|---|
401 | Invalid credentials | {"detail": "Incorrect username or password"} |
403 | Account disabled | {"detail": "User account is disabled"} |
const login = async (username, password) => { const response = await fetch('http://localhost:8501/api/v1/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) });
if (!response.ok) { const error = await response.json(); throw new Error(error.detail); }
const tokens = await response.json();
// Store tokens securely localStorage.setItem('access_token', tokens.access_token); localStorage.setItem('refresh_token', tokens.refresh_token);
return tokens;};
// Usagetry { console.log('Logged in successfully');} catch (error) { console.error('Login failed:', error.message);}import requests
def login(username: str, password: str) -> dict: """Authenticate and return tokens.""" response = requests.post( "http://localhost:8501/api/v1/auth/login", json={"username": username, "password": password} )
if response.status_code == 401: raise ValueError("Invalid credentials") elif response.status_code == 403: raise ValueError("Account disabled")
response.raise_for_status() return response.json()
# Usagetry: access_token = tokens["access_token"] refresh_token = tokens["refresh_token"] print("Login successful")except ValueError as e: print(f"Login failed: {e}")# Login and extract tokenscurl -X POST http://localhost:8501/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{ "username": "[email protected]", "password": "your_password" }'
# Store token in variable (bash)TOKEN=$(curl -s -X POST http://localhost:8501/api/v1/auth/login \ -H "Content-Type: application/json" \ | jq -r '.access_token')
echo "Access token: $TOKEN"Get a new access token using your refresh token. The old refresh token is invalidated (token rotation).
POST /api/v1/auth/refreshContent-Type: application/json
{ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "bearer"}const refreshTokens = async () => { const refreshToken = localStorage.getItem('refresh_token');
const response = await fetch('http://localhost:8501/api/v1/auth/refresh', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refresh_token: refreshToken }) });
if (!response.ok) { // Refresh token invalid/expired - redirect to login localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); window.location.href = '/login'; throw new Error('Session expired'); }
const tokens = await response.json(); localStorage.setItem('access_token', tokens.access_token); localStorage.setItem('refresh_token', tokens.refresh_token);
return tokens;};
// Auto-refresh interceptor with Axiosapi.interceptors.response.use( response => response, async error => { if (error.response?.status === 401) { try { const tokens = await refreshTokens(); error.config.headers['Authorization'] = `Bearer ${tokens.access_token}`; return api.request(error.config); } catch (refreshError) { return Promise.reject(refreshError); } } return Promise.reject(error); });import requests
class TokenManager: def __init__(self, base_url: str): self.base_url = base_url self.access_token = None self.refresh_token = None
def refresh_tokens(self) -> dict: """Refresh the access token using refresh token.""" response = requests.post( f"{self.base_url}/auth/refresh", json={"refresh_token": self.refresh_token} )
if response.status_code == 401: raise ValueError("Session expired - please login again")
response.raise_for_status() tokens = response.json()
self.access_token = tokens["access_token"] self.refresh_token = tokens["refresh_token"]
return tokensRevoke the refresh token to end the session.
POST /api/v1/auth/logoutAuthorization: Bearer <access_token>Content-Type: application/json
{ "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}{ "message": "Successfully logged out"}Retrieve the authenticated user’s profile information.
GET /api/v1/auth/meAuthorization: Bearer <access_token>{ "id": "c96ca3e5-94a1-49e3-b965-3e32ffb58b83", "username": "johndoe", "full_name": "John Doe", "role": "user", "is_active": true, "is_verified": true, "created_at": "2025-01-15T10:30:00Z", "last_login_at": "2025-12-17T14:20:00Z", "avatar_url": null, "bio": null, "preferences": { "theme": "dark", "notifications": true }}| Field | Type | Description |
|---|---|---|
id | UUID | Unique user identifier |
email | string | User’s email address |
username | string | User’s username |
full_name | string | User’s display name |
role | string | One of: user, premium, admin |
is_active | boolean | Account active status |
is_verified | boolean | Email verification status |
created_at | datetime | Account creation timestamp |
last_login_at | datetime | Last login timestamp |
Include the access token in the Authorization header for all authenticated requests:
GET /api/v1/strategiesAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...| Role | Permissions |
|---|---|
| user | Standard access - own strategies, backtests, portfolios |
| premium | Extended data access, priority task execution |
| admin | Full access - user management, system configuration |
Secure Storage
Store tokens in HttpOnly cookies or secure storage, never in plain localStorage for production.
Token Refresh
Refresh tokens 5 minutes before expiry to prevent interruption.
Logout Properly
Always call the logout endpoint to invalidate refresh tokens on the server.
HTTPS Only
Always use HTTPS in production to protect tokens in transit.