Skip to main content
POST
/
v1
/
auth
/
token
Login (Get Token)
curl --request POST \
  --url https://api.example.com/v1/auth/token \
  --header 'Content-Type: application/json' \
  --data '
{
  "client_id": "<string>",
  "client_secret": "<string>",
  "realm_id": "<string>",
  "username": "<string>",
  "password": "<string>",
  "totp_code": "<string>"
}
'
{
  "access_token": "<string>",
  "refresh_token": "<string>",
  "expires_in": 123,
  "token_type": "<string>",
  "error": "<string>"
}

Overview

Perform password-based authentication (OAuth2 password grant flow) to obtain JWT access and refresh tokens. This endpoint validates client credentials, user credentials, and optional MFA codes before issuing tokens.

Authentication Flow

  1. Client provides client_id and client_secret to prove application identity
  2. User provides username and password for authentication
  3. If MFA is enabled for the user, totp_code must be provided
  4. System validates all credentials and returns a token pair
  5. Access token is used for API requests (expires in 15 minutes)
  6. Refresh token is used to get new access tokens (expires in 24 hours)

Request Body

client_id
string
required
The OAuth client identifier obtained from Create Client.
client_secret
string
required
The OAuth client secret obtained from Create Client.
realm_id
string
required
The realm identifier where the user exists.
username
string
required
The user’s username.
password
string
required
The user’s password.
totp_code
string
6-digit TOTP code from the user’s authenticator app. Required if MFA is enabled for the user.

Response

Returns a TokenPair object:
access_token
string
JWT access token for authenticating API requests. Include in Authorization: Bearer <token> header.
refresh_token
string
JWT refresh token for obtaining new access tokens without re-authentication.
expires_in
integer
Number of seconds until the access token expires (900 seconds = 15 minutes).
token_type
string
Token type, always “Bearer”.

Token Claims

The access token JWT contains these claims:
  • sub - User ID (UUID)
  • realm - Realm ID
  • roles - Array of role names assigned to the user
  • permissions - Array of all permissions from assigned roles
  • jti - Unique token ID (for revocation)
  • token_use - “access”
  • exp - Expiration timestamp (15 minutes from issuance)
  • iat - Issued at timestamp

Example

Basic Login

cURL
curl -X POST http://localhost:8080/v1/auth/token \
  -H 'Content-Type: application/json' \
  -d '{
    "client_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "client_secret": "a1b2c3d4-e5f6-4a5b-8c7d-9e8f7a6b5c4d",
    "realm_id": "acme",
    "username": "alice",
    "password": "secret"
  }'
Response
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMzQ1In0.eyJzdWIiOiJiM2Y4YzlkMi0xYTJiLTRjNWQtOGU3Zi05YThiN2M2ZDVlNGYiLCJyZWFsbSI6ImFjbWUiLCJyb2xlcyI6WyJhZG1pbiJdLCJwZXJtaXNzaW9ucyI6WyJ1c2VyczpyZWFkIiwidXNlcnM6d3JpdGUiXSwianRpIjoiYWJjZGVmMTIzNDU2IiwidG9rZW5fdXNlIjoiYWNjZXNzIiwiZXhwIjoxNzQwMDAwOTAwLCJpYXQiOjE3NDAwMDAwMDB9.signature",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMzQ1In0.eyJzdWIiOiJiM2Y4YzlkMi0xYTJiLTRjNWQtOGU3Zi05YThiN2M2ZDVlNGYiLCJyZWFsbSI6ImFjbWUiLCJyb2xlcyI6WyJhZG1pbiJdLCJwZXJtaXNzaW9ucyI6WyJ1c2VyczpyZWFkIiwidXNlcnM6d3JpdGUiXSwianRpIjoiYWJjZGVmNjc4OTAxIiwidG9rZW5fdXNlIjoicmVmcmVzaCIsImV4cCI6MTc0MDA4NjQwMCwiaWF0IjoxNzQwMDAwMDAwfS5zaWduYXR1cmU",
  "expires_in": 900,
  "token_type": "Bearer"
}

Login with MFA

cURL
curl -X POST http://localhost:8080/v1/auth/token \
  -H 'Content-Type: application/json' \
  -d '{
    "client_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "client_secret": "a1b2c3d4-e5f6-4a5b-8c7d-9e8f7a6b5c4d",
    "realm_id": "acme",
    "username": "bob",
    "password": "secret",
    "totp_code": "123456"
  }'

Error Responses

error
string
Human-readable error message when authentication fails.
Common errors:
  • 400 Bad Request: Invalid request format or missing required fields
  • 401 Unauthorized: Invalid credentials (client, user, or MFA code)
    • "invalid client credentials" - Wrong client_id, client_secret, or realm_id mismatch
    • "invalid credentials" - Wrong username or password
    • "mfa required" - User has MFA enabled but no totp_code provided
    • "invalid mfa code" - TOTP code is incorrect or expired
  • 404 Not Found: Client or user does not exist
  • 500 Internal Server Error: Token issuance failed

Usage with API Requests

After obtaining the access token, include it in subsequent API requests:
curl -X GET http://localhost:8080/v1/some-protected-endpoint \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIs...'

Security Notes

  • Access tokens expire after 15 minutes (900 seconds)
  • Refresh tokens expire after 24 hours (86,400 seconds)
  • Tokens are signed using HS256 with rotating signing keys
  • Each token has a unique jti (JWT ID) for revocation tracking
  • Client credentials must match the realm to prevent cross-realm attacks

Build docs developers (and LLMs) love