# Authentication & API Keys

The Platform API uses **workspace-scoped API keys** for authentication - a different mechanism from the Classic API's per-user JWT tokens.

{% hint style="warning" %}
**Not the same as Classic API auth.** The Classic API at `api.amigo.ai` uses per-user JWT tokens. The Platform API uses workspace API keys with RBAC roles. See [Classic API Authentication](https://docs.amigo.ai/developer-guide/getting-started/authentication) for the other auth flow.
{% endhint %}

## How It Works

Every Platform API request requires an API key as a Bearer token:

```bash
curl https://api.platform.amigo.ai/v1/{workspace_id}/agents \
  -H "Authorization: Bearer <YOUR_API_KEY>"
```

Each key is scoped to a single workspace. The key's workspace must match the workspace in the request path - cross-workspace access is not permitted.

## API Key Lifecycle

1. **Create** a key via the API Keys endpoint, specifying a name, role, and expiration
2. **Save the key immediately** - the full key value is only returned once at creation time
3. **Use** the key as a Bearer token in all Platform API requests
4. **Revoke** the key when it's no longer needed or has been compromised

## RBAC Roles

Each API key carries a role:

| Role     | Access                                                          |
| -------- | --------------------------------------------------------------- |
| `owner`  | Full access including workspace deletion and ownership transfer |
| `admin`  | Full read/write to all workspace resources                      |
| `member` | Read/write to most resources; restricted admin operations       |
| `viewer` | Read-only access                                                |

Attempting an operation beyond the key's role returns `403 Forbidden`.

## Key Rotation

The `POST /api-keys/{key_id}/rotate` endpoint replaces a key's secret in a single atomic operation. The old secret stops working immediately and the response includes the new plaintext key exactly once.

| Parameter       | Type           | Description                    |
| --------------- | -------------- | ------------------------------ |
| `duration_days` | integer (1-90) | Expiration for the rotated key |

The rotated key inherits the original key's name, role, and permissions. You can only rotate keys you created (or any key if you have the `api_key.delete` permission).

### Usage Visibility

API key responses include a `last_used_at` timestamp showing when the key was last used to authenticate a request. Use this to identify stale keys before rotating or revoking them.

## Current Key Info

Use the `/v1/auth/me` endpoint to check the current key's workspace, expiration time, and remaining validity.

## SSO Login

The Platform API supports single sign-on (SSO) via identity federation. Users authenticate with their organization's identity provider (e.g., Google Workspace), and the platform exchanges the provider's authorization code for an Amigo JWT - the same token format as API key authentication.

### How It Works

1. The client application redirects the user to the identity provider for authentication
2. After authentication, the identity provider returns an authorization code
3. The client sends the authorization code to the Platform API token endpoint
4. The platform exchanges the code with the identity provider server-to-server and issues a JWT

### Multi-Workspace Selection

When a user has credentials on multiple workspaces, the token endpoint returns a workspace list instead of a JWT. The client re-calls the token endpoint with the selected `workspace_id` to complete authentication.

### Auto-Provisioning

Organizations can configure **provision policies** that automatically create credentials for new users on first SSO login based on their email domain. Global provision policies expand access to all workspaces in the organization. This eliminates the need to manually create credentials for each user before they can log in.

### Refresh Tokens

SSO sessions issue refresh tokens alongside the JWT. Refresh tokens are rotated on each use (the old token is invalidated when a new one is issued). Idle sessions expire after the configured timeout to meet compliance requirements.

## Multi-Factor Authentication (MFA)

The platform supports TOTP-based multi-factor authentication for user accounts.

### Enrollment Flow

1. `POST /mfa/enroll` - Generate a TOTP secret. Returns an `otpauth://` URI for scanning with an authenticator app, plus one-time recovery codes.
2. `POST /mfa/verify` - Confirm enrollment by submitting a valid TOTP code from the authenticator app.

Once enrolled, the token endpoint requires a valid TOTP code (or recovery code) alongside credentials when MFA is enforced.

### MFA Enforcement

MFA can be enforced per SSO connection. When `enforce_mfa` is enabled on a connection, users authenticating through that identity provider must complete MFA before receiving a token.

Service accounts (`client_credentials` with `service_account` principal type) are exempt from MFA enforcement since automated services cannot interact with an authenticator app.

### Recovery Codes

Recovery codes are generated during enrollment for account recovery if the authenticator device is lost. Each code can only be used once. Recovery codes are stored securely with one-way hashing.

### Admin MFA Management

| Endpoint                            | Description                                                       |
| ----------------------------------- | ----------------------------------------------------------------- |
| `GET /admin/mfa/coverage`           | MFA enrollment statistics across the workspace                    |
| `POST /admin/mfa/reset/{entity_id}` | Reset MFA enrollment for a specific user (requires re-enrollment) |

Requires `identity:admin` scope.

## IP Allowlists

Per-workspace IP allowlists restrict which IP addresses can authenticate. When configured, only requests from allowed CIDR ranges are accepted on the token endpoint.

### How It Works

* Allowlists are configured as CIDR ranges (e.g., `10.0.0.0/8`, `203.0.113.45/32`)
* When an allowlist is active, authentication requests from non-matching IPs are rejected with `403`
* IP checks are cached (5-minute TTL) for performance
* Service accounts are exempt from IP allowlist checks (required for automated service-to-service auth)
* If the cache is unavailable, IP checks fail open

### Admin IP Allowlist Management

| Endpoint                           | Description                                                      |
| ---------------------------------- | ---------------------------------------------------------------- |
| `POST /admin/ip-allowlists`        | Add a CIDR range to the workspace allowlist                      |
| `GET /admin/ip-allowlists`         | List all allowed CIDR ranges                                     |
| `DELETE /admin/ip-allowlists/{id}` | Remove a CIDR range                                              |
| `POST /admin/ip-allowlists/test`   | Test whether a specific IP address matches the current allowlist |

Requires `identity:admin` scope.

## Account Lockout & Brute Force Protection

The platform enforces progressive account lockout on failed authentication attempts:

| Failures | Lock Duration                     |
| -------- | --------------------------------- |
| 5+       | 5 minutes                         |
| 10+      | 30 minutes                        |
| 20+      | Permanent (requires admin unlock) |

Lockout is tracked per entity (API key or client) and per IP address. Successful authentication clears the lockout counter.

**Per-IP rate limiting** applies to unauthenticated grant types (`api_key`, `client_credentials`, `google_oauth`) at 60 requests/minute on the `/token` endpoint. Already-authenticated grants (`agent_session`, `refresh_token`) are exempt.

The system fails open - if the lockout store is unavailable, authentication proceeds normally.

**Admin lockout management** (requires `identity:admin` scope):

| Endpoint                                  | Description                            |
| ----------------------------------------- | -------------------------------------- |
| `POST /admin/lockout/unlock/{identifier}` | Unlock a locked account                |
| `GET /admin/lockout/locked-accounts`      | List all currently locked accounts     |
| `GET /admin/lockout/status/{identifier}`  | Check lockout status for an identifier |

Locked responses return `403` with a `Retry-After` header for timed lockouts.

## Session Enforcement

Sessions are enforced with idle timeouts and concurrent session limits. A background process periodically revokes idle and expired sessions.

### Idle Timeout

Sessions are revoked after a configurable period of inactivity:

| Session Type                      | Default Idle Timeout | Notes                                                          |
| --------------------------------- | -------------------- | -------------------------------------------------------------- |
| User sessions (developer console) | 15 minutes           | HIPAA-compliant default                                        |
| Agent sessions (voice calls)      | 1 hour               | Matches agent session TTL; voice agents don't refresh mid-call |

Configurable per-session between 5 minutes and 24 hours. Activity is tracked on each authenticated request.

### Concurrent Session Limits

Each entity is limited to a maximum number of active sessions per workspace:

| Session Type   | Max Concurrent Sessions | Eviction Behavior                         |
| -------------- | ----------------------- | ----------------------------------------- |
| User sessions  | 5                       | Oldest session evicted when limit reached |
| Agent sessions | 50                      | Oldest session evicted when limit reached |

Agent sessions have a higher limit because a single service entity (e.g., a voice agent) handles many simultaneous calls.

### Session Metadata

Sessions now track IP address and user agent for audit and security visibility.

### Session Management Endpoints

**User endpoints** (any authenticated user):

| Endpoint                        | Description                                                    |
| ------------------------------- | -------------------------------------------------------------- |
| `GET /sessions`                 | List active sessions for the current entity                    |
| `DELETE /sessions`              | Revoke all sessions for the current entity (logout everywhere) |
| `DELETE /sessions/{session_id}` | Revoke a specific session                                      |

**Admin endpoints** (requires `identity:admin` scope):

| Endpoint                             | Description                                                                 |
| ------------------------------------ | --------------------------------------------------------------------------- |
| `GET /sessions/admin`                | List all active sessions with optional entity/workspace filters, pagination |
| `DELETE /sessions/admin/{entity_id}` | Revoke all sessions for a specific entity (optional workspace scope)        |

All revocation actions are audit-logged.

## API Reference

* [API Keys](https://docs.amigo.ai/api-reference/readme/platform/api-keys)
* [Auth](https://docs.amigo.ai/api-reference/readme/platform/auth)
* [Sessions](https://docs.amigo.ai/api-reference/readme/platform/sessions)
