Authentication API¶
The Authentication API provides endpoints for authentication and identity management.
Base URL¶
Authentication¶
Most authentication endpoints require an API key. Some endpoints may require user JWT tokens.
Endpoints¶
Exchange API Key for Service Actor Token¶
Exchange a long-lived API key for a short-lived JWT token for a service actor.
Endpoint: POST /public/v1/identity/auth/token/exchange
Authentication: API key with provision:token:exchange scope
Request:
Request Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
serviceActorId | string | Yes | ID of the service actor to generate token for |
Response:
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 900,
"expiresAt": 1710000900,
"actorType": "service",
"organisationId": "507f1f77bcf86cd799439011",
"scopes": ["analytics:query", "analytics:write"]
}
Response Fields:
| Field | Type | Description |
|---|---|---|
token | string | JWT token for authenticated requests |
expiresIn | number | Token expiration time in seconds (default: 900) |
expiresAt | number | Token expiration timestamp (Unix epoch) |
actorType | string | Always "service" for service actor tokens |
organisationId | string | Organization ID from the service actor |
scopes | string[] | Capabilities granted to the service actor |
Example:
curl -X POST https://api.fermi.dev/public/v1/identity/auth/token/exchange \
-H "Authorization: Bearer fmk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"serviceActorId": "507f1f77bcf86cd799439011"
}'
Error Responses¶
Missing Scope¶
{
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized - Invalid API key, missing scope, or permission denied"
}
Solution: Ensure your API key has provision:token:exchange scope.
Service Actor Not Found¶
Solution: Verify the service actor ID is correct and belongs to your organization.
Organization Mismatch¶
{
"status": 403,
"error": "Forbidden",
"message": "Service actor's parent organisation must match API key's organization"
}
Solution: Ensure the service actor belongs to the same organization as your API key.
Rate Limits¶
- Token Exchange: 100 requests per minute per API key
Best Practices¶
- Cache tokens until near expiration (tokens last 15 minutes)
- Handle expiration gracefully with automatic refresh
- Use service actors for automated systems
- Monitor token usage and exchange frequency
Examples¶
Python Example¶
import requests
import os
import time
api_key = os.getenv("FERMI_API_KEY")
service_actor_id = os.getenv("FERMI_SERVICE_ACTOR_ID")
def exchange_token(api_key, service_actor_id):
response = requests.post(
"https://api.fermi.dev/public/v1/identity/auth/token/exchange",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
},
json={"serviceActorId": service_actor_id}
)
response.raise_for_status()
return response.json()
# Exchange for token
token_data = exchange_token(api_key, service_actor_id)
token = token_data["token"]
expires_at = token_data["expiresAt"]
print(f"Token expires at: {time.ctime(expires_at)}")
print(f"Scopes: {token_data['scopes']}")
JavaScript Example¶
const apiKey = process.env.FERMI_API_KEY;
const serviceActorId = process.env.FERMI_SERVICE_ACTOR_ID;
async function exchangeToken(apiKey, serviceActorId) {
const response = await fetch(
'https://api.fermi.dev/public/v1/identity/auth/token/exchange',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ serviceActorId })
}
);
if (!response.ok) {
throw new Error(`Token exchange failed: ${response.status}`);
}
return await response.json();
}
// Usage
exchangeToken(apiKey, serviceActorId)
.then(data => {
console.log(`Token expires at: ${new Date(data.expiresAt * 1000).toISOString()}`);
console.log(`Scopes: ${data.scopes.join(', ')}`);
})
.catch(error => console.error('Error:', error));
Next Steps¶
- Token Exchange Guide - Detailed guide on token exchange
- Service Actors - Learn about service actors
- API Reference Overview - Return to API reference index