7 min read Updated July 6, 2026

Authentication

The Tamandua API supports multiple authentication methods to accommodate different use cases, from server-to-server integrations to agent enrollment and web dashboard access.

API Keys

API keys are the recommended authentication method for server-to-server integrations, scripts, and third-party applications.

API Key Format

API keys follow a structured format for easy identification:

tam_<environment>_<random_string>
  • tam_live_ - Production keys
  • tam_dev_ - Development keys
  • tam_test_ - Test environment keys

Example: tam_live_7a8b9c0d1e2f3g4h5i6j7k8l9m0n

Creating an API Key

Endpoint: POST /api/v1/api-keys
curl -X POST "https://api.tamandua.io/api/v1/api-keys" \
  -H "Authorization: Bearer <session_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": {
      "name": "Production Integration",
      "description": "SIEM integration for alert forwarding",
      "permissions": ["alerts:read", "alerts:write", "events:read"],
      "scope": "organization",
      "rate_limit_per_minute": 500,
      "rate_limit_per_hour": 5000,
      "expires_at": "2025-12-31T23:59:59Z",
      "allowed_ips": ["10.0.0.0/8", "192.168.1.100"]
    }
  }'
Response:
{
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Production Integration",
    "description": "SIEM integration for alert forwarding",
    "key_prefix": "tam_live_",
    "permissions": ["alerts:read", "alerts:write", "events:read"],
    "scope": "organization",
    "rate_limit_per_minute": 500,
    "rate_limit_per_hour": 5000,
    "expires_at": "2025-12-31T23:59:59Z",
    "allowed_ips": ["10.0.0.0/8", "192.168.1.100"],
    "is_active": true,
    "last_used_at": null,
    "created_at": "2024-01-15T10:30:00Z"
  },
  "raw_key": "tam_live_7a8b9c0d1e2f3g4h5i6j7k8l9m0n",
  "message": "API key created. Save this key securely - it cannot be retrieved later."
}
Important: The raw_key is only returned once at creation time. Store it securely.

Using an API Key

Include the API key in the Authorization header:

curl -X GET "https://api.tamandua.io/api/v1/alerts" \
  -H "Authorization: Bearer tam_live_7a8b9c0d1e2f3g4h5i6j7k8l9m0n"

Listing API Keys

Endpoint: GET /api/v1/api-keys
curl -X GET "https://api.tamandua.io/api/v1/api-keys" \
  -H "Authorization: Bearer <session_token>"
Response:
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Production Integration",
      "key_prefix": "tam_live_",
      "permissions": ["alerts:read", "alerts:write"],
      "is_active": true,
      "last_used_at": "2024-01-15T14:20:00Z",
      "created_at": "2024-01-10T09:00:00Z"
    }
  ]
}

Rotating an API Key

Endpoint: POST /api/v1/api-keys/:id/rotate

Creates a new key with the same settings and deactivates the old one:

curl -X POST "https://api.tamandua.io/api/v1/api-keys/550e8400-e29b-41d4-a716-446655440000/rotate" \
  -H "Authorization: Bearer <session_token>"
Response:
{
  "data": {
    "id": "660e8400-e29b-41d4-a716-446655440001",
    "name": "Production Integration (rotated)",
    "key_prefix": "tam_live_",
    "is_active": true
  },
  "raw_key": "tam_live_newkey123456789abcdefghijk",
  "old_key_id": "550e8400-e29b-41d4-a716-446655440000",
  "message": "API key rotated. Save the new key securely - it cannot be retrieved later."
}

Deactivating an API Key

Endpoint: POST /api/v1/api-keys/:id/deactivate
curl -X POST "https://api.tamandua.io/api/v1/api-keys/550e8400-e29b-41d4-a716-446655440000/deactivate" \
  -H "Authorization: Bearer <session_token>"

Deleting an API Key

Endpoint: DELETE /api/v1/api-keys/:id
curl -X DELETE "https://api.tamandua.io/api/v1/api-keys/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer <session_token>"

JWT Tokens (Agent Authentication)

JWT tokens are used for agent-to-server authentication. Agents receive a JWT during enrollment and can refresh it automatically.

Token Structure

Agent JWT tokens contain:

{
  "agent_id": "uuid",
  "generation": 5,
  "iat": 1705312200,
  "exp": 1705398600,
  "iss": "tamandua"
}
  • agent_id: The unique agent identifier
  • generation: Token generation number (increments on rotation)
  • iat: Issued at timestamp
  • exp: Expiration timestamp
  • iss: Token issuer

Checking Token Status

Endpoint: GET /api/v1/agents/auth/status
curl -X GET "https://api.tamandua.io/api/v1/agents/auth/status" \
  -H "Authorization: Bearer <agent_jwt_token>"
Response:
{
  "valid": true,
  "agent_id": "550e8400-e29b-41d4-a716-446655440000",
  "generation": 5,
  "issued_at": "2024-01-15T10:00:00Z",
  "expires_at": "2024-01-16T10:00:00Z",
  "refresh_eligible": true,
  "time_to_expiry_seconds": 43200,
  "percent_elapsed": 50.0,
  "refresh_count": 2,
  "revoked": false
}

Refreshing a Token

Endpoint: POST /api/v1/agents/auth/refresh

Tokens can be refreshed when they reach 80% of their TTL:

curl -X POST "https://api.tamandua.io/api/v1/agents/auth/refresh" \
  -H "Authorization: Bearer <current_agent_jwt>"
Response:
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_at": "2024-01-17T10:00:00Z",
  "generation": 6,
  "refresh_count": 3,
  "message": "Token refreshed successfully"
}
Error Responses:
{
  "error": "Token refresh not allowed yet",
  "message": "Token must reach refresh window (typically 80% of TTL) before it can be refreshed"
}

Revoking Agent Tokens

Endpoint: POST /api/v1/agents/auth/revoke

Revoke tokens for a specific agent (requires admin authentication):

curl -X POST "https://api.tamandua.io/api/v1/agents/auth/revoke" \
  -H "Authorization: Bearer <admin_api_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "550e8400-e29b-41d4-a716-446655440000",
    "reason": "security_incident",
    "all_generations": true
  }'
Response:
{
  "status": "revoked",
  "agent_id": "550e8400-e29b-41d4-a716-446655440000",
  "revoked_count": 3,
  "reason": "security_incident"
}

Token Statistics

Endpoint: GET /api/v1/agents/auth/stats/:agent_id
curl -X GET "https://api.tamandua.io/api/v1/agents/auth/stats/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer <admin_api_key>"

Scopes and Permissions

API keys and tokens can have granular permissions:

Available Scopes

ScopeDescription
organizationAccess to organization resources
tenantMulti-tenant access
globalSystem-wide access (admin only)

Available Permissions

PermissionDescription
agents:readView agent information
agents:writeModify agent settings
agents:manageFull agent control including isolation
alerts:readView alerts
alerts:writeUpdate alert status
events:readQuery telemetry events
events:writeSubmit events (agent only)
response:executeExecute response actions
rules:readView detection rules
rules:writeCreate/modify detection rules
users:readView user information
users:manageManage users and permissions
integrations:manageConfigure SIEM/SOAR integrations
settings:manageModify organization settings

Permission Check Example

When a request lacks required permissions:

{
  "error": "insufficient_permissions",
  "required": ["alerts:write"],
  "message": "Your API key does not have permission to perform this action"
}

Session Authentication (Web Dashboard)

The web dashboard uses session-based authentication with CSRF protection.

Login

Endpoint: POST /login
curl -X POST "https://app.tamandua.io/login" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "email=user@example.com&password=yourpassword"

CSRF Token

For session-authenticated API requests, include the CSRF token:

curl -X POST "https://app.tamandua.io/api/v1/alerts/bulk" \
  -H "Cookie: _tamandua_session=xxx" \
  -H "X-CSRF-Token: abc123" \
  -H "Content-Type: application/json" \
  -d '{"alert_ids": ["id1", "id2"], "action": "resolve"}'

Web3 Wallet Authentication Preview

Tamandua includes a preview wallet-authentication flow for deployments that explicitly enable it:

Request Challenge

Endpoint: POST /wallet/challenge
curl -X POST "https://app.tamandua.io/wallet/challenge" \
  -H "Content-Type: application/json" \
  -d '{
    "wallet_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f..."
  }'
Response:
{
  "challenge": "Sign this message to authenticate: nonce=abc123xyz",
  "nonce": "abc123xyz"
}

Wallet Login

Endpoint: POST /wallet/login
curl -X POST "https://app.tamandua.io/wallet/login" \
  -H "Content-Type: application/json" \
  -d '{
    "wallet_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f...",
    "signature": "0x...",
    "nonce": "abc123xyz"
  }'

SSO / SAML Authentication

Enterprise SSO is supported via SAML 2.0:

SAML Metadata

Endpoint: GET /auth/sso/saml/metadata/:provider_id

SAML Login

Endpoint: GET /auth/sso/saml/login/:provider_id

SAML ACS (Assertion Consumer Service)

Endpoint: POST /auth/sso/saml/acs/:provider_id

OAuth 2.0 / OIDC

Authorize: GET /auth/sso/oauth/authorize/:provider_id Callback: GET /auth/sso/oauth/callback/:provider_id

IP Restrictions

API keys can be restricted to specific IP addresses:

{
  "allowed_ips": [
    "10.0.0.0/8",
    "192.168.1.100",
    "2001:db8::/32"
  ]
}

When a request comes from a non-allowed IP:

{
  "error": "ip_not_allowed",
  "message": "This API key cannot be used from your IP address"
}

Security Best Practices

  1. Never commit API keys to version control
  2. Use environment variables for API keys in code
  3. Rotate keys regularly (every 90 days recommended)
  4. Use IP restrictions for production integrations
  5. Set expiration dates on keys when possible
  6. Use minimal permissions - only request scopes you need
  7. Monitor key usage via the dashboard
  8. Revoke compromised keys immediately

Rate Limiting by Auth Type

Auth TypeRate LimitNotes
API KeyPer-key limitsConfigurable per key
JWT (Agent)100/minFixed for agent stability
Session1000/minPer user session

Error Codes

ErrorHTTP CodeDescription
missing_token401No authentication provided
invalid_token401Token is malformed or invalid
token_expired401Token has expired
token_revoked401Token has been revoked
generation_mismatch401A newer token generation exists
ip_not_allowed403Request IP not in allowlist
insufficient_permissions403Missing required permissions
key_deactivated401API key has been deactivated