Authentication
The API uses JWT bearer tokens for authentication. You'll get two tokens when you log in — each with a different purpose and lifetime.
Token types
| Token | Lifetime | Purpose |
|---|---|---|
| Access token | Short-lived | Passed as Authorization: Bearer <token> on every request |
| Refresh token | Long-lived | Used to obtain a new access token when the current one expires |
Recommended flow
┌─────────┐ ┌───────────┐
│ Login │────────→ │ Get both │
│ │ │ tokens │
└─────────┘ └─────┬─────┘
│
┌─────▼─────┐
┌──────│ Use API │◄────────┐
│ │ normally │ │
│ └─────┬─────┘ │
│ │ │
│ ┌─────▼─────┐ ┌─────┴─────┐
│ │ 401? │──→│ Refresh │
│ └───────────┘ │ token │
│ └───────────┘
│
┌─────▼──────┐
│ Refresh │
│ also 401? │──→ Re-login
└────────────┘
Step by step
-
Login — Call
POST /v1/auth/loginwith your email and password. Store both theaccessTokenandrefreshToken. -
Use the access token — Include it in every API request:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs... -
Handle expiration — When you receive a
401 Unauthorizedresponse, your access token has expired. CallPOST /v1/auth/refreshwith your refresh token to get a new access token. -
Re-login if needed — If the refresh token itself is expired or revoked, you'll get a
401from the refresh endpoint too. In that case, log in again withPOST /v1/auth/login.
Security best practices
- Store tokens securely — never expose tokens in client-side code, URLs, or logs
- Refresh proactively — instead of waiting for a
401, you can decode the JWT to check its expiration time and refresh before it expires - Revoke on logout — call
POST /v1/auth/revokewhen a user session ends to invalidate the refresh token - Revoke all in emergencies — if you suspect a token has been compromised, call
POST /v1/auth/revoke-allto invalidate all sessions