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

# Authentication

> How API tokens, scopes, and machine-to-machine flows work across the Voyant SDKs.

Every Voyant API and SDK authenticates with a Voyant API token. One token works across Cloud, Connect, and Data; its scopes decide what it is allowed to do.

## API tokens

A token is sent as a bearer token in the `Authorization` header:

```
Authorization: Bearer <your-api-token>
```

The SDKs do this for you when you pass `apiKey`:

```ts theme={null}
import { createVoyantCloudClient } from "@voyant-travel/cloud-sdk";

const client = createVoyantCloudClient({
  apiKey: process.env.VOYANT_API_KEY!,
});
```

Mint tokens in the dashboard tokens UI, or with the [CLI](/docs/cli/overview) after `voyant login`. Keep tokens on the server. They carry the scopes that authorize real actions, so they should never ship in a browser bundle.

## Scopes

Tokens are scoped per service and per action. A route checks the scope it declares against the token's scopes, and rejects the call if it is missing. Examples:

| Action                     | Scope              |
| -------------------------- | ------------------ |
| Send an SMS                | `sms:send`         |
| Read a vault secret        | `vault:read`       |
| Publish a realtime message | `realtime:publish` |
| Read geography data        | `data:geo:read`    |

Each service page lists the scopes its methods need. Grant a token only the scopes it actually uses.

<Note>
  If a read comes back empty or a call is rejected, check the token's scopes first. A missing scope is the most common cause, and for some data products an entitlement gap surfaces as empty results rather than an error.
</Note>

## Machine-to-machine tokens

Connect supports OAuth client credentials for machine-to-machine flows. Provision a client, then exchange its credentials for a short-lived bearer token:

```ts theme={null}
import { createVoyantConnectClient } from "@voyant-travel/connect-sdk";

const client = createVoyantConnectClient({ apiKey: process.env.VOYANT_API_KEY! });

const token = await client.oauth.issueToken({ /* client credentials */ });
// token.access_token, token.expires_in, token.scope
```

Both static API keys and minted access tokens hit the same scope-checked routes. The access token's `scope` claim must include the scope the route declares.

## Short-lived client tokens for browsers

Some services let a browser connect directly without your API key. Realtime is the main example: you mint a short-lived, capability-scoped client token on the server and hand it to the front end, which uses it to open a WebSocket. The API key never leaves your server. See [Realtime](/docs/services/realtime).

## Base URL

Every API is served from:

```
https://api.voyant.travel
```

You can override `baseUrl` on any client for testing or self-hosted environments.

## CLI credentials

The CLI stores cloud credentials in `~/.voyant/credentials.json` (mode 0600), keyed by API URL and organization, so you can be logged into several environments and organizations at once. On every cloud command it resolves a token in this order:

1. A `--token <value>` flag.
2. The `VOYANT_CLOUD_API_KEY` environment variable.
3. The stored credential for the resolved API URL and active organization.

The active organization is chosen by `--org` → `VOYANT_CLOUD_ORG` → `voyant org use` → the sole logged-in org. See the [CLI overview](/docs/cli/overview) for login flows and organizations.
