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

# API Keys

> Mint, scope, rotate, and verify gavAI API keys

API keys authenticate the gavAI CLI, SDK, and any signed-API consumer you build. Each key carries a fixed set of scopes that constrain what it can read or mutate.

## Mint a key

1. Sign in to `/console/settings/api-keys` as a workspace admin.
2. Click **Mint new key**, name it (e.g. `ci-pipeline`), pick the scopes it needs.
3. Copy the secret immediately — it is shown **exactly once**.

Keys are stored hashed; gavAI cannot recover the plaintext. If you lose it, revoke and re-mint.

## Scopes

Scopes are namespaced `<surface>:<action>`. Common ones:

| Scope                                    | Meaning                                |
| ---------------------------------------- | -------------------------------------- |
| `workspace:read`                         | Read workspace + member listings       |
| `workspace:audit`                        | Read tenant audit log                  |
| `workspace:billing`                      | Read invoices, manage portal session   |
| `workspace:members`                      | Invite / remove / role-change members  |
| `workspace:admin`                        | Full admin parity (use sparingly)      |
| `apps:read`, `apps:write`                | Read / publish tenant apps             |
| `submissions:read`, `submissions:reveal` | Read submissions; reveal masked fields |

Issue the narrowest scope that satisfies the job — admin parity is rarely the right choice for automation.

## Signing requests

The CLI / SDK sign requests with HMAC-SHA256 over a canonical string:

```
<HTTP-METHOD> \n
<request-path> \n
<unix-timestamp-seconds> \n
<sha256-hex(payload-bytes)>
```

Send three headers:

| Header              | Value                                              |
| ------------------- | -------------------------------------------------- |
| `Authorization`     | `Bearer <key-id>`                                  |
| `X-Gavai-Signature` | `v1=<hex(hmac_sha256(secret, canonical_string))>`  |
| `X-Gavai-Timestamp` | The same unix-timestamp used in `canonical_string` |

### Sample (Node)

```ts theme={null}
import { createHmac, createHash } from "node:crypto";

function signRequest(opts: {
  method: string;
  path: string;
  body: Uint8Array;
  keyId: string;
  secret: string;
}): Record<string, string> {
  const ts = Math.floor(Date.now() / 1000).toString();
  const payloadDigest = createHash("sha256").update(opts.body).digest("hex");
  const canonical = `${opts.method.toUpperCase()}\n${opts.path}\n${ts}\n${payloadDigest}`;
  const sig = createHmac("sha256", opts.secret).update(canonical).digest("hex");
  return {
    Authorization: `Bearer ${opts.keyId}`,
    "X-Gavai-Signature": `v1=${sig}`,
    "X-Gavai-Timestamp": ts,
  };
}
```

### Sample (Python)

```python theme={null}
import hashlib
import hmac
import time

def sign_request(method, path, body, key_id, secret):
    ts = str(int(time.time()))
    payload_digest = hashlib.sha256(body).hexdigest()
    canonical = f"{method.upper()}\n{path}\n{ts}\n{payload_digest}"
    sig = hmac.new(secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()
    return {
        "Authorization": f"Bearer {key_id}",
        "X-Gavai-Signature": f"v1={sig}",
        "X-Gavai-Timestamp": ts,
    }
```

## Verification on the server side

gavAI rejects requests where:

* The timestamp is more than 5 minutes off the server clock (replay protection).
* The HMAC computed over the canonical string does not match.
* The `key_id` is revoked or the scope does not cover the requested action.

Use a constant-time comparison for the HMAC check.

## Rotation

When a key needs rotating:

1. Mint a new key with the same scopes.
2. Roll over the key in your secret store / config.
3. Revoke the old key from `/console/settings/api-keys`.

Revoked keys reject immediately. There is no grace period — coordinate the rollover before revoking.

## Audit trail

Each mint, revoke, and authenticated request is recorded in the tenant audit log (`/console/activity`). Use this to spot keys that aren't doing what you expect.
