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...",
"expires_at": "2024-03-16T10:00:00Z",
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
"user": {
"id": "user-123",
"username": "your-username",
"email": "you@company.com",
"roles": ["admin"]
}
}

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:

Okta

# Configure Okta integration
POST /api/v1/admin/sso/okta
{
"domain": "your-company.okta.com",
"client_id": "0oaxxxxxxxxxxxxx",
"client_secret": "xxxxxxxxxxxxxxxxxxxxxxxx"
}

Users can then authenticate via Okta:

GET /api/v1/auth/sso/okta/login
→ Redirects to Okta login
→ Returns with authorization code
→ Exchange code for Infracast token

Azure AD

POST /api/v1/admin/sso/azure
{
"tenant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"client_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"client_secret": "xxxxxxxxxxxxxxxxxxxxxxxx"
}

SAML 2.0

For SAML providers:

POST /api/v1/admin/sso/saml
{
"entity_id": "https://idp.company.com",
"sso_url": "https://idp.company.com/saml/sso",
"certificate": "-----BEGIN CERTIFICATE-----\n..."
}

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/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