> For the complete documentation index, see [llms.txt](https://docs.amigo.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.amigo.ai/developer-guide/getting-started/authentication.md).

# Authentication

Amigo uses a two-tiered authentication system for secure API access. This guide covers the credential flow, API key generation, testing, and advanced authentication options.

{% hint style="warning" %}
**Classic API authentication.** This page covers the Classic API's two-tier authentication (API key to JWT). The Platform API uses workspace-scoped API keys as Bearer tokens instead. See [Platform API Authentication](/developer-guide/platform-api/platform-api/authentication.md).
{% endhint %}

## The Credential Flow

Amigo uses a two-credential system for secure API access. Your Amigo representative provisions your organization and its initial `Admin` user; everything from there is self-serve.

1. **Generate an API key** (one-time or rotate periodically)
   * Create via the Admin Dashboard or the API endpoint
   * Produces `api_key_id` and `api_key`
   * Long-lived credential for machine-to-machine authentication
   * Keep it secret to prevent unauthorized access
2. **Exchange the API key for a JWT token** (per session or application startup)
   * Call `POST /v1/{org}/user/signin_with_api_key` with the API key credentials
   * Returns an `id_token` (a JWT) and its `expires_at` expiry time
   * Short-lived token representing an authenticated user session
3. **Use the JWT in all API calls**
   * Include it in the header: `Authorization: Bearer {jwt}`
   * The JWT grants access to conversations, users, and other endpoints
   * It can act on behalf of other users, as permitted by their roles and permissions

{% hint style="danger" %}
**Critical: API Key is not a JWT Token**

Wrong: `Authorization: Bearer {api_key}` Correct: `Authorization: Bearer {jwt}`

Never use the API key directly in Bearer headers. Always exchange it for a JWT first via the signin endpoint.
{% endhint %}

### Flow

```mermaid
%%{init: {"theme": "base", "themeVariables": {"actorBkg": "#083241", "actorTextColor": "#FFFFFF", "actorBorder": "#083241", "signalColor": "#575452", "signalTextColor": "#100F0F", "labelBoxBkgColor": "#F1EAE7", "labelBoxBorderColor": "#D7D2D0", "labelTextColor": "#100F0F", "loopTextColor": "#100F0F", "noteBkgColor": "#F1EAE7", "noteBorderColor": "#D7D2D0", "noteTextColor": "#100F0F", "activationBkgColor": "#E8E2EB", "activationBorderColor": "#083241", "altSectionBkgColor": "#F1EAE7", "altSectionColor": "#100F0F"}}}%%
sequenceDiagram
  autonumber
  participant Dev as Developer/Admin
  participant API as Amigo API
  participant App as Your App / SDK

  Note over Dev,API: Create API key (one-time or rotate periodically)
  Dev->>API: POST /v1/{org}/organization/api_key/
  API-->>Dev: 201 Created { api_key_id, api_key }

  Note over App,API: Exchange API key for JWT (machine-to-machine)
  App->>API: POST /v1/{org}/user/signin_with_api_key
  API-->>App: 200 OK { id_token, expires_at }

  Note over App,API: Use JWT for HTTP requests
  App->>API: Authorization: Bearer {jwt}
  API-->>App: 200 OK

  Note over App,API: For WebSocket realtime
  App->>API: Sec-WebSocket-Protocol:<br/>bearer.authorization.amigo.ai.{jwt}
  API-->>App: Connected
```

## Generating API Keys

A service account makes API keys for use with other services. When your organization is set up in Amigo, an `Admin` user is created for adding more users. To confirm you are logged in as the `Admin` role, check that the tag appears in the top right corner of the admin dashboard.

You have two options for generating API keys.

{% tabs %}
{% tab title="Admin Dashboard" %}

1. Log in to your service account.
2. Navigate to `https://<your-org-id>.amigo.ai/admin/settings`.
3. Click **Create API Key** and select the duration.
4. Store the API key and key ID securely (they cannot be retrieved later).
   {% endtab %}

{% tab title="Programmatic (Recommended)" %}

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**Permission boundaries** API keys cannot impersonate users with higher privileges than the key creator.
{% endhint %}

## Authentication Token Generation

Exchange your API key for a JWT token to authenticate API calls.

{% openapi src="<https://api.amigo.ai/v1/openapi.json>" path="/v1/{organization}/user/signin\_with\_api\_key" method="post" %}
<https://api.amigo.ai/v1/openapi.json>
{% endopenapi %}

## Testing with Postman or Scalar

When testing with API clients like Postman, Scalar, or Insomnia, follow the quick start flow below.

### Quick start flow

1. **Generate an API key** using one of the methods above. You will have `api_key`, `api_key_id`, and your `user_id`.
2. **Call the signin endpoint** to exchange for a JWT (see the embedded reference above).
3. **Use the JWT as a Bearer token** for all other API calls.

{% hint style="warning" %}
**Critical: the signin endpoint uses headers**

When calling `/user/signin_with_api_key`, pass credentials as **HTTP headers** rather than in the request body:

* `x-api-key: {your-api-key}`
* `x-api-key-id: {your-api-key-id}`
* `x-user-id: {your-user-id}`

The response contains `{ "id_token": "...", "expires_at": "..." }`. The `id_token` is the JWT you use as the Bearer token.
{% endhint %}

{% hint style="info" %}
**Where to find credentials**

* `api_key`, `api_key_id`, and `user_id`: all available at `https://<your-org-id>.amigo.ai/admin/settings/api-keys`
* `user_id`: also available in user details at `https://<your-org-id>.amigo.ai/admin/users/{user_id}`
  {% endhint %}

Once you have the JWT, use it for all subsequent requests.

```http
Authorization: Bearer {id_token-from-signin-response}
```

## Regional Endpoints and Dedicated Clusters

* Use the regional base URL that matches your organization's residency. See [Regions & Endpoints](/developer-guide/getting-started/regions-and-endpoints.md) for the full list.
* For tenants on dedicated clusters, include the `x-mongo-cluster-name` header when instructed (mandatory for Create Organization).

## Security Best Practices

### API key rotation

1. **Create new keys** before current keys expire.
2. **Transition applications** to use the new credentials.
3. **Revoke old keys** after a successful transition.
4. **Automate rotation** to prevent authentication failures.

### Additional security measures

* **Environment variables.** Never hardcode credentials.
* **Access control.** Apply the principle of least privilege.
* **Audit logs.** Monitor API key usage.
* **Secure storage.** Use a secret management solution.

## Advanced Authentication

Most integrations only need the API key to JWT flow above. The methods in this section cover specialized deployments.

### DPoP (Sender-Constrained Tokens)

By default, the platform issues standard Bearer tokens, sent in the `Authorization` header:

```http
Authorization: Bearer <access_token>
```

The platform also supports DPoP (Demonstration of Proof-of-Possession) sender-constrained tokens per RFC 9449. DPoP binds tokens to a cryptographic key held by the client, so even if a token is intercepted, it cannot be used without the corresponding private key.

To use DPoP:

1. **Generate an EC key pair** on the client (P-256, P-384, or P-521).
2. **Create a DPoP proof JWT** for each request with the following header and claims:
   * Header: `typ` set to `dpop+jwt`, `alg` set to `ES256`/`ES384`/`ES512`, and `jwk` containing the public key.
   * Claims: `htm` (HTTP method), `htu` (HTTP URL without query parameters), `iat` (issued at), and `jti` (unique identifier). Do not include an `exp` claim.
3. **Send the proof** in the `DPoP` header on the token request.
4. **Receive a DPoP-bound token** - the response will have `token_type` set to `DPoP` and the access token will contain a confirmation claim binding it to your key.
5. **Include a DPoP proof on every request** that uses the access token, including refresh token grants.

When refreshing a DPoP-bound token, you must include a valid DPoP proof signed by the same key. The refresh token is not rotated on each use - because the token is sender-constrained, replay by a different client is not possible, eliminating the need for rotation and the race conditions it can cause.

#### Token Response

The token response includes a `token_type` field that indicates whether the token is a standard `Bearer` token or a sender-constrained `DPoP` token:

| Field           | Type      | Description                            |
| --------------- | --------- | -------------------------------------- |
| `access_token`  | `string`  | The access token                       |
| `token_type`    | `string`  | `Bearer` or `DPoP`                     |
| `expires_in`    | `integer` | Token lifetime in seconds              |
| `scope`         | `string`  | Space-separated list of granted scopes |
| `refresh_token` | `string`  | Refresh token (if applicable)          |
| `session_id`    | `string`  | Session identifier (if applicable)     |

### HTTP Basic Authentication (Experimental)

{% hint style="warning" %}
**Experimental feature.** HTTP Basic Auth is experimental and subject to change. Use the API key to JWT exchange for production integrations.
{% endhint %}

An alternative authentication method is available using HTTP Basic Auth, which supports cross-organization authorization.

**Format:**

```http
Authorization: Basic base64({org_id}_{user_id}:{jwt})
```

The username is `{org_id}_{user_id}` and the password is the Amigo-issued JWT that identifies the user.

**Key features:**

* Combines organization, user, and the user's Amigo-issued JWT into a single header
* Supports cross-organization authentication (a user in org A authenticating against org B)
* Useful for scenarios where the standard two-step API key to JWT flow is impractical

**Example:**

```bash
# Encode credentials
CREDENTIALS=$(echo -n "${ORG_ID}_${USER_ID}:${JWT}" | base64)

curl --request GET \
     --url 'https://api.amigo.ai/v1/<YOUR-ORG-ID>/service/' \
     --header "Authorization: Basic ${CREDENTIALS}"
```

## CLI Authentication (Agent Forge)

When using the Agent Forge CLI, authentication is configured via environment variables in your `.env.{env}` file. Two methods are supported.

### Method 1: API key authentication

Set all three API key variables to use API key auth. This method also supports user impersonation via the `--user` flag.

```env
API_KEY=your-api-key
API_KEY_ID=your-api-key-id
API_KEY_USER_ID=your-user-id
```

### Method 2: Firebase authentication (recommended)

Set `GOOGLE_TENANT_ID` (and omit the API key fields) to use Firebase-based Google Sign-In with device code flow. When using the device code flow, the CLI displays a user code and directs you to Google's device authorization page (`https://www.google.com/device`). After signing in, you enter the code shown in your terminal and approve the request. Tokens are cached locally (with owner-only file permissions) and refresh automatically.

```env
GOOGLE_TENANT_ID=your-tenant-id
```

```bash
# One-time login per environment
forge auth login -e myorg

# Output:
# Visit: https://www.google.com/device
# Enter code: ABCD-EFGH
# Waiting for authentication...
# Authenticated as you@example.com
```

{% hint style="info" %}
**Auth method selection.** The CLI picks the auth method based on which environment variables are set. If all three API key fields are present, API key auth is used. Otherwise, Firebase auth is used. Subsequent commands reuse cached tokens and refresh them silently.
{% endhint %}

{% hint style="warning" %}
**Impersonation limitation.** The `--user` flag on conversation commands (smoke-test, simulate, simulate-step) requires API key authentication. Firebase auth does not support user impersonation.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.amigo.ai/developer-guide/getting-started/authentication.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
