> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Authenticate with the KnoxCall API using API keys or OAuth 2.1 + DPoP

KnoxCall supports two authentication paths, both fully supported, both safe to mix:

1. **Long-lived API keys** (`tk_live_…`, `tk_test_…`, `AKE…`) — the original path, still works everywhere.
2. **OAuth 2.1 short-lived access tokens** (`kc_live_…`, `kc_test_…`) — minted via `POST /oauth/token`, expire in 1 hour, optionally sender-constrained with DPoP (RFC 9449).

If you've used Auth0, Okta, AWS Cognito, Stripe Connect, or any modern OAuth provider, our OAuth surface will feel identical — every endpoint conforms to a published IETF RFC.

## Quick start — OAuth 2.1

```bash theme={"dark"}
# Mint a 1-hour token from your existing API key
TOKEN=$(curl -s -X POST https://api.knoxcall.com/oauth/token \
  -u "tk_abcd1234:rest_of_key" \
  -d "grant_type=client_credentials" \
  | jq -r .access_token)

# Use it like any Bearer token
curl -H "Authorization: Bearer $TOKEN" https://api.knoxcall.com/v1/routes
```

Your existing `tk_…` API key becomes the OAuth `client_id` + `client_secret`:

* `client_id` = `tk_abcd1234` (everything before the second underscore)
* `client_secret` = the remainder

The OAuth path adds:

* **1-hour TTL** instead of long-lived
* **Scope narrowing** — request a subset of your key's permissions per call
* **DPoP sender-constraint** (optional) — proof-of-possession of a keypair required per request

## OAuth 2.1 endpoints

| Endpoint                                      | Purpose                                      | RFC      |
| --------------------------------------------- | -------------------------------------------- | -------- |
| `POST /oauth/token`                           | Mint access + refresh tokens                 | RFC 6749 |
| `POST /oauth/device_authorization`            | Start a device-code flow (headless machines) | RFC 8628 |
| `POST /oauth/introspect`                      | Validate a token (relying-party use)         | RFC 7662 |
| `POST /oauth/revoke`                          | Revoke a token                               | RFC 7009 |
| `GET /.well-known/oauth-authorization-server` | Discovery                                    | RFC 8414 |

Supported grant types:

* `client_credentials` — server-to-server, the simplest path
* `authorization_code` + PKCE — human consent flow (with refresh tokens). Public clients may register loopback redirect URIs per RFC 8252 — `http://127.0.0.1`, `http://[::1]`, and `http://localhost` match on any port at authorization time, so native and CLI apps can receive the callback locally.
* `urn:ietf:params:oauth:grant-type:device_code` — RFC 8628 device-code flow for headless/SSH machines: `POST /oauth/device_authorization` returns a user code, the user approves it at `/oauth/activate` on any browser, and the device polls the token endpoint. This is what `knoxcall login --device` uses.
* `refresh_token` — single-use rotation with family-detection theft protection
* `urn:ietf:params:oauth:grant-type:token-exchange` — workload identity federation (GitHub Actions, GCP, AWS, Azure, Vercel)

## DPoP — sender-constrained tokens (RFC 9449)

For tenants requiring the highest security tier, request DPoP-bound tokens. Send a DPoP proof JWT on the token request; the issued token is bound to your keypair via the `cnf.jkt` claim. Every subsequent API call must carry a fresh DPoP proof signed by the same key.

```typescript theme={"dark"}
// Use the SDK — DPoP is transparent
import { KnoxCall } from "@knoxcall/sdk";
const client = new KnoxCall({ tenant: "acme", dpop: "always" });
```

## Workload identity federation (RFC 8693)

Run on GitHub Actions, GCP, AWS, Azure, or Vercel? **You don't need an API key at all.** The SDK detects your platform and exchanges its OIDC token for a KnoxCall access token automatically.

```yaml theme={"dark"}
# GitHub Actions example — zero stored secrets
- run: |
    npm install @knoxcall/sdk
    node my-script.js
  env:
    KNOXCALL_TENANT: acme
permissions:
  id-token: write
```

Configure the trust binding once in the KnoxCall dashboard under **Settings → Workload Identity**. Subsequent CI runs auto-authenticate.

## Using the SDK (recommended)

KnoxCall ships first-party SDKs for Node.js/TypeScript, Python, Go, PHP, and Ruby (plus a Terraform provider and browser/React Elements) — see the [SDKs overview](/sdks/overview) for the full family. Every SDK handles token minting, caching, retries, idempotency keys, and DPoP for you.

<CodeGroup>
  ```bash Node.js / TypeScript — install theme={"dark"}
  npm install @knoxcall/sdk
  ```

  ```typescript Node.js / TypeScript theme={"dark"}
  import { KnoxCall } from "@knoxcall/sdk";

  const client = new KnoxCall({ tenant: "acme" });
  const routes = await client.routes.list();
  ```

  ```python Python theme={"dark"}
  from knoxcall import KnoxCall

  # Credentials from KNOXCALL_CLIENT_ID / KNOXCALL_CLIENT_SECRET
  client = KnoxCall()
  page = client.routes.list()
  routes = page["data"]
  ```

  ```go Go theme={"dark"}
  client, err := knoxcall.New(knoxcall.Options{})
  if err != nil {
      log.Fatal(err)
  }
  page, err := client.Routes.List(context.Background(), nil)
  // page.Data holds the routes
  ```

  ```php PHP theme={"dark"}
  $client = new KnoxCall(); // env-configured
  $page   = $client->routes->list();
  $routes = $page['data'];
  ```

  ```ruby Ruby theme={"dark"}
  client = KnoxCall::Client.new # env-configured
  page   = client.routes.list
  routes = page["data"]
  ```

  ```bash cURL (raw REST) theme={"dark"}
  curl https://api.knoxcall.com/v1/routes \
    -H "Authorization: Bearer tk_live_abc123..."
  ```
</CodeGroup>

Every SDK handles credential auto-detection, token caching, refresh, retries, and DPoP signing — your code just calls methods. Prefer raw REST? Pass your API key as `Authorization: Bearer <key>` and parse the JSON response.

## Log in once with the CLI

On a developer machine, skip keys and env vars entirely. Every KnoxCall SDK package ships the `knoxcall` command (pip, npm, gem, Composer, `go install` — same surface, same credentials file); it runs the authorization-code + PKCE flow in your browser (or the RFC 8628 device-code flow with `--device`) and stores the credential in `~/.knoxcall/credentials.json`:

```bash theme={"dark"}
pip install knoxcall              # or your ecosystem's equivalent — every SDK ships the CLI
knoxcall login                    # opens your browser (PKCE); prints the URL too
knoxcall login --device           # headless/SSH machines: device-code flow
knoxcall whoami                   # show the signed-in tenant
knoxcall logout                   # revoke + remove the stored credential
```

Every KnoxCall SDK — Node.js, Python, Go, PHP, and Ruby — picks the file up automatically, so a zero-argument constructor just works:

```python theme={"dark"}
from knoxcall import KnoxCall

client = KnoxCall()  # tenant and base URL come from the login
```

Access tokens refresh themselves; refreshes are cross-process safe (file lock + atomic rotation of the single-use refresh token). Behind the scenes, `knoxcall login` uses the reserved `knoxcall-cli` client alias, which provisions a per-tenant system OAuth client on first login — you'll see it on the OAuth Clients page, where it is visible but protected. See the [SDKs overview](/sdks/overview#log-in-once-with-the-cli) for profiles (`KNOXCALL_PROFILE`), sandbox login, and the full credential-resolution order.

## Postman / Insomnia / Bruno

Import the [official KnoxCall Postman collection](https://knoxcall.com/postman). It uses Postman's native OAuth 2.0 support — sign in once via the **Authorization** tab, and every saved request inherits the token.

For other tools, point them at the OAuth 2.0 discovery URL: `https://api.knoxcall.com/.well-known/oauth-authorization-server`.

***

## API Key Types

KnoxCall uses API keys to authenticate requests to the Management API. There are three types of keys, each with a distinct prefix:

| Key Type          | Prefix     | Environment | Description                                                                  |
| ----------------- | ---------- | ----------- | ---------------------------------------------------------------------------- |
| Standard          | `tk_live_` | Production  | Full access to production resources. Available on all plans.                 |
| Enterprise Access | `AKE`      | Production  | Enhanced keys with configurable scopes and expiration. Enterprise plan only. |
| Test              | `tk_test_` | Sandbox     | Full access to sandbox resources. Safe for development and testing.          |

<Note>
  Key prefixes make it easy to identify which environment a key belongs to at a glance. This follows the same live/test paradigm used by Stripe and other modern APIs.
</Note>

## Creating API Keys

### Via the Dashboard

1. Log in to the [KnoxCall Dashboard](https://knoxcall.com).
2. Navigate to **Settings** in the sidebar.
3. Scroll to the **API Keys** section.
4. Click **Create API Key**.
5. Give your key a descriptive name (e.g., "CI/CD Pipeline", "Backend Server").
6. Copy the key immediately -- it will only be shown once.

<Warning>
  API keys are displayed only once at creation time. If you lose a key, you must revoke it and create a new one. KnoxCall never stores keys in plain text after initial creation.
</Warning>

### Via the API

You can also create API keys programmatically:

```bash theme={"dark"}
curl -X POST https://api.knoxcall.com/v1/api-keys \
  -H "Authorization: Bearer tk_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Deployment Key"
  }'
```

Response:

```json theme={"dark"}
{
  "data": {
    "key_id": "ak_3f8a9b2c",
    "api_key": "tk_live_newkey789...",
    "key_prefix": "tk_live_newk",
    "key_type": "standard",
    "name": "Deployment Key",
    "message": "Store this API key securely. It will not be shown again."
  },
  "meta": {
    "request_id": "req_..."
  }
}
```

<Note>
  The `api_key` field in the response is the only time the full API key is returned. Store it securely.
</Note>

## Production vs. Sandbox

KnoxCall provides completely separate production and sandbox environments, following the same live/test key paradigm popularized by Stripe. Routes, secrets, environments, webhooks, vaults, crypto keys, PKI authorities, OAuth clients, and workflows are all isolated between the two modes — nothing leaks across.

<CardGroup cols={2}>
  <Card title="Production (Live)" icon="server">
    **Management API:** `https://api.knoxcall.com/v1`

    **Proxy traffic:** `https://{slug}.knoxcall.com/{route}`

    * Uses `tk_live_` or `AKE` prefixed keys
    * Routes proxy real traffic to live upstream APIs
    * Secrets contain real credentials
    * Usage counts against your plan limits
    * Changes affect your live integrations immediately
  </Card>

  <Card title="Sandbox (Test)" icon="flask">
    **Management API:** `https://sandbox.knoxcall.com/v1`

    **Proxy traffic:** `https://sandbox-{slug}.knoxcall.com/{route}`

    * Uses `tk_test_` prefixed keys
    * Routes, secrets, and clients are isolated from production
    * Safe for development, testing, and CI/CD
    * No impact on production traffic or billing
    * Mirrors production API behavior exactly
  </Card>
</CardGroup>

<Warning>
  Using a test key against the production API (or vice versa) will return a `403` error with the type `wrong_key_type`. Make sure your environment configuration matches the correct base URL and key type.
</Warning>

### Dashboard toggle

The admin dashboard has a **Live / Test** toggle in the bottom-left of the sidebar (look for the flask icon). Click it to switch the entire dashboard between modes — every page (Routes, Secrets, Vaults, API Keys, Webhooks, etc.) refetches and shows only the data for the active mode. An amber banner across the top of the screen confirms when you are in Test mode.

While in Test mode:

* Creating an API key automatically produces a `tk_test_` test key (the standard / Enterprise Access Key options are hidden).
* Creating any other resource (route, secret, vault, etc.) stamps it as sandbox — it is invisible from Live mode.
* Existing live resources are not visible; you start with an empty sandbox until you populate it.

Switching back to Live mode restores the production view immediately. Your selection persists across browser sessions.

### Using the SDK in sandbox mode

Both the Node and Go SDKs accept a `sandbox: true` option which auto-resolves the management and proxy base URLs to the sandbox hostnames:

<CodeGroup>
  ```typescript Node.js theme={"dark"}
  import { KnoxCall } from "@knoxcall/sdk";

  const client = new KnoxCall({
    tenant: "acme",
    sandbox: true, // → https://sandbox.knoxcall.com + https://sandbox-acme.knoxcall.com
  });

  // Use a tk_test_ key — required for sandbox.
  ```

  ```go Go theme={"dark"}
  import "github.com/knoxcall/knoxcall-go/knoxcall"

  client, err := knoxcall.New(knoxcall.Options{
      Tenant:  "acme",
      Sandbox: true, // → https://sandbox.knoxcall.com + https://sandbox-acme.knoxcall.com
      APIKey:  "tk_test_...",
  })
  ```
</CodeGroup>

Equivalent environment variables work everywhere (CI, Docker, etc.): set `KNOXCALL_BASE_URL=https://sandbox.knoxcall.com` and `KNOXCALL_PROXY_BASE_URL=https://sandbox-{slug}.knoxcall.com`.

### Audit logs

Every audit log entry is stamped with `details.sandbox: true|false` so you can filter live vs test activity in the Audit Logs page or via the `/v1/audit-logs` endpoint. Background jobs (cron, queue workers) always emit `sandbox: false`.

## Using API Keys

Pass your API key in the `Authorization` header as a Bearer token, or use the `x-api-key` header.

### Examples

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl https://api.knoxcall.com/v1/routes \
    -H "Authorization: Bearer tk_live_abc123..."
  ```

  ```python Python theme={"dark"}
  import requests

  headers = {
      "Authorization": "Bearer tk_live_abc123..."
  }

  # List all routes
  response = requests.get(
      "https://api.knoxcall.com/v1/routes",
      headers=headers
  )

  routes = response.json()["data"]
  for route in routes:
      print(f"{route['name']} - {route['target_base_url']}")
  ```

  ```javascript Node.js theme={"dark"}
  const API_KEY = process.env.KNOXCALL_API_KEY;

  const response = await fetch("https://api.knoxcall.com/v1/routes", {
    headers: {
      Authorization: `Bearer ${API_KEY}`
    }
  });

  const { data: routes } = await response.json();
  routes.forEach(route => {
    console.log(`${route.name} - ${route.target_base_url}`);
  });
  ```

  ```php PHP theme={"dark"}
  <?php

  $apiKey = getenv('KNOXCALL_API_KEY');

  $ch = curl_init('https://api.knoxcall.com/v1/routes');
  curl_setopt_array($ch, [
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_HTTPHEADER => [
          "Authorization: Bearer {$apiKey}"
      ]
  ]);

  $response = curl_exec($ch);
  curl_close($ch);

  $data = json_decode($response, true);
  foreach ($data['data'] as $route) {
      echo "{$route['name']} - {$route['target_base_url']}\n";
  }
  ```
</CodeGroup>

### Using the x-api-key Header

If your HTTP client or framework makes it difficult to set the `Authorization` header, you can use the `x-api-key` header instead:

<CodeGroup>
  ```bash cURL theme={"dark"}
  curl https://api.knoxcall.com/v1/routes \
    -H "x-api-key: tk_live_abc123..."
  ```

  ```python Python theme={"dark"}
  import requests

  response = requests.get(
      "https://api.knoxcall.com/v1/routes",
      headers={"x-api-key": "tk_live_abc123..."}
  )
  ```

  ```javascript Node.js theme={"dark"}
  const response = await fetch("https://api.knoxcall.com/v1/routes", {
    headers: { "x-api-key": process.env.KNOXCALL_API_KEY }
  });
  ```

  ```php PHP theme={"dark"}
  <?php

  $ch = curl_init('https://api.knoxcall.com/v1/routes');
  curl_setopt_array($ch, [
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_HTTPHEADER => [
          "x-api-key: " . getenv('KNOXCALL_API_KEY')
      ]
  ]);

  $response = curl_exec($ch);
  curl_close($ch);
  ```
</CodeGroup>

## Authentication Errors

When authentication fails, the API returns one of these error types:

| Error Type                | Status | Cause                                                    | Solution                                                                |
| ------------------------- | ------ | -------------------------------------------------------- | ----------------------------------------------------------------------- |
| `authentication_required` | 401    | No API key provided                                      | Add the `Authorization` or `x-api-key` header to your request           |
| `invalid_api_key`         | 401    | Key is invalid, revoked, or expired                      | Check that the key is correct and has not been revoked in the dashboard |
| `wrong_key_type`          | 403    | Test key used on production, or live key used on sandbox | Match the key type to the correct base URL                              |
| `subscription_inactive`   | 403    | Tenant subscription is paused or cancelled               | Update your billing information in the dashboard                        |

Example error response:

```json theme={"dark"}
{
  "error": {
    "type": "invalid_api_key",
    "message": "The API key provided is invalid or has been revoked.",
    "request_id": "req_a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}
```

## Security Best Practices

<CardGroup cols={2}>
  <Card title="Never expose keys in client-side code" icon="eye-slash">
    API keys grant full access to your KnoxCall configuration. Never embed them in frontend JavaScript, mobile apps, or any code that runs in the browser.
  </Card>

  <Card title="Use environment variables" icon="terminal">
    Store API keys in environment variables or a secrets manager. Never hard-code them in source files or commit them to version control.
  </Card>

  <Card title="Rotate keys regularly" icon="arrows-rotate">
    Create new keys and revoke old ones on a regular cadence. If a key is compromised, revoke it immediately from the dashboard.
  </Card>

  <Card title="Use the principle of least privilege" icon="shield-check">
    On Enterprise plans, use scoped access keys (AKE) to limit what each key can do. For standard plans, create separate keys per service so you can revoke individually.
  </Card>
</CardGroup>

### Environment Variable Setup

<CodeGroup>
  ```bash Linux / macOS theme={"dark"}
  # Add to your shell profile (~/.bashrc, ~/.zshrc, etc.)
  export KNOXCALL_API_KEY="tk_live_abc123..."

  # Or use a .env file with dotenv
  echo 'KNOXCALL_API_KEY=tk_live_abc123...' >> .env
  ```

  ```powershell Windows (PowerShell) theme={"dark"}
  # Set for current session
  $env:KNOXCALL_API_KEY = "tk_live_abc123..."

  # Set permanently for current user
  [System.Environment]::SetEnvironmentVariable("KNOXCALL_API_KEY", "tk_live_abc123...", "User")
  ```

  ```yaml Docker / docker-compose.yml theme={"dark"}
  services:
    app:
      environment:
        - KNOXCALL_API_KEY=tk_live_abc123...
      # Or reference a .env file
      env_file:
        - .env
  ```

  ```yaml CI/CD (GitHub Actions) theme={"dark"}
  # Store as a repository secret, then reference in workflow:
  env:
    KNOXCALL_API_KEY: ${{ secrets.KNOXCALL_API_KEY }}
  ```
</CodeGroup>

<Warning>
  Never add `.env` files containing API keys to version control. Add `.env` to your `.gitignore` file.
</Warning>

### Key Rotation Procedure

1. Create a new API key in the [dashboard](https://knoxcall.com) or via the API.
2. Update your application's environment variables with the new key.
3. Deploy the updated configuration.
4. Verify that requests succeed with the new key.
5. Revoke the old key in the dashboard.

<Note>
  Both the old and new keys will work simultaneously until you revoke the old one. This allows zero-downtime rotation.
</Note>
