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

# Authentication

> Choose a human PAT or a Service Account credential without mixing their responsibilities.

export function AirctrlWordmark() {
  return <span className="airctrl-wordmark" aria-label="AIRCTRL">
      <span aria-hidden="true" className="airctrl-wordmark-air">AIR</span>
      <span aria-hidden="true" className="airctrl-wordmark-ctrl">CTRL</span>
    </span>;
}

<AirctrlWordmark /> has two developer credentials. Choose the one that matches who is running the code.

| Credential            | Use it for                             | Visible prefix  |
| --------------------- | -------------------------------------- | --------------- |
| Personal Access Token | Work performed by a person             | `sk-actrl-pat-` |
| Service Account token | Unattended work performed by a machine | `sk-actrl-sa-`  |

Both values are bearer tokens. Send only the complete token in the `Authorization` header.

```http theme={}
Authorization: Bearer <token>
```

The credentials are not interchangeable. A human PAT can use all 59 public operations when RBAC
permits them. A Service Account can use the 10 read operations intended for unattended work. See
[Feature availability](/reference/availability) for the exact boundary.

## Personal Access Tokens

Create a PAT in **Settings > Access tokens**. <AirctrlWordmark /> shows the complete token once.

A PAT identifies you and stays within its account and project scope. RBAC still decides whether each action is allowed. A token never adds permissions by itself.

Use a PAT with:

* The REST API.
* `createClient` from `@airctrl/sdk`.
* `airctrl login` or `AC_TOKEN` in the CLI.
* `AIRCTRL_MCP_API_TOKEN` in human MCP mode.

## Service Account credentials

Create the Service Account, assign its custom roles and projects, and provision its credential in the <AirctrlWordmark /> dashboard. These security actions are intentionally Web-only.

The downloaded credential bundle contains the API URL, bearer token, credential ID, Service Account ID, and a private capability used locally. Keep the whole bundle together. Do not split fields across unrelated credentials.

Use the bundle with the SDK:

```ts theme={}
import { readFile } from 'node:fs/promises'
import { createClient, type SaCredentialBundleV1 } from '@airctrl/sdk'

const bundle = JSON.parse(
  await readFile(process.env.AIRCTRL_SA_BUNDLE_PATH!, 'utf8'),
) as SaCredentialBundleV1

const airctrl = createClient({
  baseUrl: bundle.baseUrl,
  auth: bundle.bearer,
  credential: {
    credentialId: bundle.credentialId,
    capPrivateKeyB64: bundle.capPrivateKeyB64,
  },
})
```

For the CLI, provide one complete active credential through the runtime environment:

| Variable                    | Bundle field       |
| --------------------------- | ------------------ |
| `AC_API_BASE_URL`           | `baseUrl`          |
| `AC_TOKEN`                  | `bearer`           |
| `AC_SA_CREDENTIAL_ID`       | `credentialId`     |
| `AC_SA_CAP_PRIVATE_KEY_B64` | `capPrivateKeyB64` |
| `AC_SA_SERVICE_ACCOUNT_ID`  | `serviceAccountId` |

<AirctrlWordmark /> fails closed when the Service Account fields are incomplete or contradictory. It does not silently treat an incomplete machine credential as a human PAT.

For MCP, map the same active bundle to `AIRCTRL_MCP_API_URL`, `AIRCTRL_MCP_API_TOKEN`, `AIRCTRL_MCP_SA_CREDENTIAL_ID` and `AIRCTRL_MCP_SA_CAP_PRIVATE_KEY_B64`. `AIRCTRL_MCP_SA_SERVICE_ACCOUNT_ID` is optional. Do not set the human vault passphrase in Service Account mode.

## Account context

Many account-level requests require `x-account-id`. This header selects context; it does not grant access. The API binds every request to the account carried by the credential and rejects attempts to widen that scope.

With a human PAT, use `listAccounts()` or `GET /v1/accounts` to discover valid account IDs. A Service
Account does not enumerate accounts: its credential is already bound to one account, and its work is
selected with the project or resource ID assigned to it. SDK methods that need account context take
`accountId` explicitly.

## Vault passphrase

The vault passphrase is not an API credential.

* The token authenticates the caller.
* The passphrase unlocks human cryptographic material locally.
* <AirctrlWordmark /> never needs the passphrase for metadata-only operations.

Do not send the passphrase in an HTTP body, URL, prompt, log, or source file. The SDK, CLI, and local MCP process use it only in the process that performs decryption.

## Token safety

* Load credentials from your runtime environment or secret storage.
* Never place a token in a URL or query parameter.
* Never commit a credential bundle.
* Rotate or revoke credentials from the dashboard when exposure is suspected.
* Use the smallest roles and project grants that complete the task.
