> For the complete documentation index, see [llms.txt](https://verbatim-ai.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://verbatim-ai.gitbook.io/docs/integration/access-keys.md).

# Access Keys

An **access token** is a short-lived, opaque credential you hand to clients you don't fully trust — most importantly, code running in a **browser**. It carries a mandatory **scope**, so it can only do what you explicitly allow, and it expires quickly.

Sent as a header on `/v1/` requests:

```
X-Access-Token: 8Jf3kQ2p...
```

***

## Why access tokens exist

Your RSA **private key** must never reach a browser or a mobile app — anyone who has it can impersonate your whole organization. But frontends still need to call the API (to run queries, upload files, power the chatbot widget…).

The answer is a two-tier model:

```
Backend (holds private key, mints RSA JWT)
        │  POST /v1/auth/access-token   (authenticated with the JWT)
        ▼
Access token  (short-lived, scoped, opaque)
        │  X-Access-Token: <token>
        ▼
Browser / widget / untrusted client  → calls /v1/ endpoints
```

The untrusted client only ever sees a token that is short-lived, narrowly scoped, and revocable.

***

## Creating an access token

`POST /v1/auth/access-token` — **authenticated with an RSA JWT** (call it from your backend).

**Request body**

| Field    | Required | Default | Description                                                                                                       |
| -------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------- |
| `scope`  | **yes**  | —       | Non-empty list of `DOMAIN:ACTION` entries. See [scopes](/docs/integration/authentication.md#scopes-domainaction). |
| `ttl`    | no       | `3600`  | Lifetime in seconds. Must be **> 10**.                                                                            |
| `issuer` | no       | —       | Free-text label for the system requesting the token (e.g. `widget-frontend`).                                     |
| `email`  | no       | —       | Email of the end-user the token is for.                                                                           |
| `userId` | no       | —       | Your identifier for that end-user.                                                                                |

> **Scope is mandatory.** Unlike an RSA JWT (where an empty scope means "unrestricted"), an access token with no scope is rejected at creation. This keeps browser-facing tokens least-privilege by design.

**Example**

```bash
curl -X POST https://staging-api.verbatim-ai.com/v1/auth/access-token \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
        "ttl": 3600,
        "issuer": "widget-frontend",
        "email": "user@example.com",
        "scope": ["corpus:read", "session:read", "session:create", "post:read", "post:create"]
      }'
```

**Response**

```json
{
  "token": "8Jf3kQ2p...",
  "scope": ["corpus:read", "session:read", "session:create", "post:read", "post:create"],
  "createdAt": "2026-07-07T10:00:00Z",
  "expiresAt": "2026-07-07T11:00:00Z"
}
```

Return `token` to the frontend. It is opaque — there is nothing to decode client-side.

### Choosing scopes

Grant the minimum the client needs.

| Client                  | Typical scope                                                                   |
| ----------------------- | ------------------------------------------------------------------------------- |
| Read-only Q\&A widget   | `["corpus:read", "session:read", "session:create", "post:read", "post:create"]` |
| Upload-only integration | `["doc:create", "doc:read"]`                                                    |
| Dashboard reading usage | `["usage:read", "corpus:read"]`                                                 |

Valid domains: `config`, `auth`, `session`, `doc`, `corpus`, `post`, `usage`, `agent`. Valid actions: `create`, `read`, `update`, `delete`. Each entry must match exactly, e.g. `doc:create`.

***

## Using an access token

Send it as `X-Access-Token` on any `/v1/` request the token's scope permits:

```js
const res = await fetch(
  "https://staging-api.verbatim-ai.com/v1/post/q?sessionId=" + sessionId +
    "&body=" + encodeURIComponent("What is the refund policy?"),
  { headers: { "X-Access-Token": accessToken } }
);
const data = await res.json();
```

If the token is missing, expired, or its scope doesn't cover the request, the API returns **403 Forbidden**.

> Do **not** send both `Authorization` and `X-Access-Token`. If both are present the bearer token takes precedence and the access token is ignored.

***

## Revoking an access token

`DELETE /v1/auth/access-token/{token}` — invalidates the token immediately; in-flight requests using it fail right after.

```bash
curl -X DELETE \
  "https://staging-api.verbatim-ai.com/v1/auth/access-token/8Jf3kQ2p..." \
  -H "Authorization: Bearer $JWT"
```

Revoke on sign-out or when you suspect a leak. Even so, always set a **short `ttl`** so tokens expire on their own.

***

## Checking identity — `whoami`

`GET /v1/auth/whoami` returns the identity resolved from the caller's credential (organization, user id, email, name). Use it to bootstrap a UI after sign-in or to confirm a token is still valid.

```bash
curl -H "X-Access-Token: $ACCESS_TOKEN" \
     https://staging-api.verbatim-ai.com/v1/auth/whoami
```

***

## Using an access token with the chatbot widget

The Verbatim chatbot widget authenticates with an access token, sent as the `X-Access-Token` header on every call it makes. To wire it up:

1. On your backend, mint an access token scoped for the widget (read corpora + run queries), as shown above.
2. Pass it to `mountChatbotWidget({ accessToken, corpusIds, ... })`.
3. Because tokens are short-lived, expose a small backend endpoint the page can call to fetch a fresh token, and refresh before expiry.

Full widget options, theming and troubleshooting are in the [Chatbot widget installation guide](https://gitlab.com/verbatim.cloud/backend/genai-server/-/tree/develop/docs/\[./widget-installation-guide.md]\(https:/verbatim-ai.gitbook.io/docs/widget-website?fallback=true\)/README.md).

***

## Access tokens vs RSA JWT — quick comparison

|                   | RSA JWT                              | Access token                               |
| ----------------- | ------------------------------------ | ------------------------------------------ |
| Header            | `Authorization: Bearer <jwt>`        | `X-Access-Token: <token>`                  |
| Signed by         | You (private RSA key)                | Verbatim (server-side)                     |
| Where it may live | Backend only                         | Backend **and** untrusted clients          |
| Scope             | Optional (empty = unrestricted)      | **Mandatory**, non-empty                   |
| Revoke            | Deactivate/delete the key            | `DELETE /v1/auth/access-token/{token}`     |
| Create it with    | `scripts/build_keys.py` or a JWT lib | `POST /v1/auth/access-token` (needs a JWT) |

***

**Next:** [Security best practices →](/docs/integration/security.md) · [API domains & conventions →](/docs/integration/api-domains.md) · [Widget installation →](https://gitlab.com/verbatim.cloud/backend/genai-server/-/tree/develop/docs/\[./widget-installation-guide.md]\(https:/verbatim-ai.gitbook.io/docs/widget-website?fallback=true\)/README.md)


---

# 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://verbatim-ai.gitbook.io/docs/integration/access-keys.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.
