Skip to main content

Authentication

Infracast uses JWT (JSON Web Tokens) for API authentication. All API requests (except health checks) require a valid token.

Getting a Token​

Login Flow​

Exchange username/password for an access token:

curl -X POST https://api.infracast.io/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{
"username": "your-username",
"password": "your-password"
}'

Response:

{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user_id": "user-123",
"username": "your-username",
"account_id": "acct-...",
"tenant_id": "tnt-...",
"workspace_id": "wsp-...",
"role": "tenant-admin",
"onboarding_completed": true
}

JWT Claims​

The issued JWT carries:

ClaimDescription
user_idThe authenticated user
account_idTop-level billing entity
tenant_idCustomer organization the user is operating in
workspace_idActive workspace (data scope) within the tenant
roleTenant role: tenant-admin, operator, viewer, or platform system-admin
iat / exp / jtiStandard timing/identity claims

All non-account/non-workspace endpoints are auto-scoped by workspace_id. To switch workspaces without re-authenticating, call POST /api/v1/auth/switch-workspace (returns a new token bound to the target workspace). To switch tenants, call POST /api/v1/auth/select-tenant.

Token Lifetime​

Token TypeLifetimeUse
Access Token1 hourAPI requests
Refresh Token7 daysGet new access token

Using Tokens​

Include the token in the Authorization header:

curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
https://api.infracast.io/api/v1/tenants/my-tenant/nodes

Python Example​

import requests

# Get token
auth_response = requests.post(
"https://api.infracast.io/api/v1/auth/token",
json={"username": "admin", "password": "secret"}
)
token = auth_response.json()["token"]

# Use token
headers = {"Authorization": f"Bearer {token}"}
nodes = requests.get(
"https://api.infracast.io/api/v1/tenants/my-tenant/nodes",
headers=headers
)

JavaScript Example​

// Get token
const authResponse = await fetch('https://api.infracast.io/api/v1/auth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: 'admin', password: 'secret' })
});
const { token } = await authResponse.json();

// Use token
const nodes = await fetch('https://api.infracast.io/api/v1/tenants/my-tenant/nodes', {
headers: { 'Authorization': `Bearer ${token}` }
});

Refreshing Tokens​

When your access token expires, use the refresh token to get a new one:

curl -X POST https://api.infracast.io/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4..."
}'

Response (new access token):

{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": "2024-03-16T11:00:00Z"
}
Token Refresh Strategy

Refresh your token proactively before it expires (e.g., when 5 minutes remain). This prevents request failures due to expired tokens.

API Keys (Service Accounts)​

For server-to-server integrations, use API keys instead of user tokens:

Create an API Key​

curl -X POST https://api.infracast.io/api/v1/api-keys \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-cd-integration",
"tenants": ["my-tenant"],
"permissions": ["nodes:read", "findings:read"],
"expires_at": "2025-03-16T00:00:00Z"
}'

Response:

{
"id": "key-abc123",
"name": "ci-cd-integration",
"key": "ic_live_abc123xyz789...",
"created_at": "2024-03-16T00:00:00Z",
"expires_at": "2025-03-16T00:00:00Z"
}
Store Securely

The API key is only shown once. Store it securely (e.g., in a secrets manager). It cannot be retrieved later.

Using API Keys​

API keys are used the same way as tokens:

curl -H "Authorization: Bearer ic_live_abc123xyz789..." \
https://api.infracast.io/api/v1/tenants/my-tenant/nodes

Key Permissions​

PermissionDescription
nodes:readList and get nodes
nodes:writeCreate/update/delete nodes
findings:readList and get findings
findings:writeAccept risk, resolve findings
jobs:readList and get jobs
jobs:writeCreate, start, cancel jobs
reports:readGenerate and download reports
admin:*Full admin access

SSO / OAuth 2.0​

Infracast supports enterprise SSO providers:

SSO is configured per tenant. The {tenantID} below is the ID of the tenant whose SSO you are configuring.

API paths corrected 2026-09-14

SSO configuration endpoints are tenant-scoped (/api/v1/tenants/{tenantID}/sso), not global admin endpoints. The previously documented paths /api/v1/admin/sso/okta, /api/v1/admin/sso/azure, and /api/v1/admin/sso/saml do not exist.

Configure SSO (OIDC / SAML)​

# Create or replace the SSO configuration for a tenant
PUT /api/v1/tenants/{tenantID}/sso
{
"provider": "okta", # or "azure", "google", or any OIDC/SAML provider
"issuer": "https://your-company.okta.com",
"client_id": "0oaxxxxxxxxxxxxx",
"client_secret": "xxxxxxxxxxxxxxxxxxxxxxxx"
}

# For SAML providers, supply the IdP metadata URL instead
PUT /api/v1/tenants/{tenantID}/sso
{
"provider": "saml",
"metadata_url": "https://idp.company.com/saml/metadata"
}

# Test the connection
POST /api/v1/tenants/{tenantID}/sso/test

# Read current config
GET /api/v1/tenants/{tenantID}/sso

# Remove SSO config
DELETE /api/v1/tenants/{tenantID}/sso

Once configured, users authenticate via:

GET  /api/v1/auth/oidc/{slug}/login      → OIDC login redirect
POST /api/v1/auth/saml/{slug}/acs → SAML Assertion Consumer Service
GET /api/v1/auth/saml/{slug}/metadata → SP metadata for your IdP
GET /api/v1/auth/saml/{slug}/slo → SAML Single Log-Out

The {slug} is the URL-safe tenant identifier shown in Settings → SSO.

Multi-Tenant Access​

Users can have different roles across tenants:

{
"user": {
"id": "user-123",
"tenants": [
{ "id": "prod", "role": "admin" },
{ "id": "staging", "role": "viewer" },
{ "id": "dev", "role": "editor" }
]
}
}

Token permissions are scoped to the requested tenant.

Security Best Practices​

Token Storage​

EnvironmentRecommendation
BrowserHttpOnly cookie or secure storage
Mobile AppSecure keychain/keystore
ServerEnvironment variable or secrets manager
CI/CDSecret variables (GitHub Secrets, etc.)

Token Rotation​

  • Rotate API keys periodically (90 days recommended)
  • Use short-lived access tokens (1 hour)
  • Revoke tokens when users leave

IP Allowlisting​

Restrict API key usage by IP:

POST /api/v1/tenants/{tenantID}/api-keys
{
"name": "restricted-key",
"allowed_ips": ["10.0.0.0/8", "192.168.1.100"]
}

Troubleshooting​

"Invalid token" Error​

{"error": {"code": "UNAUTHORIZED", "message": "Invalid or expired token"}}

Causes:

  • Token has expired (check expires_at)
  • Token was revoked
  • Wrong environment (dev token on prod)

Solutions:

  • Refresh the token
  • Re-authenticate
  • Check you're using the correct API URL

"Forbidden" Error​

{"error": {"code": "FORBIDDEN", "message": "Insufficient permissions"}}

Causes:

  • User doesn't have access to this tenant
  • API key missing required permission
  • Role doesn't allow this action

Solutions:

  • Check user/key permissions
  • Request elevated access from admin
  • Use a different API key with correct scopes