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

# Authentication

> Authenticate with RunTools APIs, SDK, and CLI

## API Keys

Use API keys for servers, scripts, CI jobs, and SDK clients. Keep them out of browser code and mobile clients.

Create and rotate keys from **Dashboard → Credentials → API Keys**, the CLI, or the SDK:

```bash theme={null}
runtools auth keys list
runtools auth keys create "ci-production" --scope "*"
runtools auth keys revoke <key-id>
```

```typescript theme={null}
// The full key value is returned ONCE, at creation — store it immediately.
const created = await rt.auth.createKey({
  name: 'ci-production',
  scopes: ['sandbox:*', 'agent:run'],
  expiresIn: '90d',
});
console.log(created.key); // rt_live_… (only present on the create response)

const keys = await rt.auth.listKeys();
await rt.auth.revokeKey(created.id);
```

API keys authenticate with `X-API-Key`:

```bash theme={null}
curl https://api.runtools.ai/v1/sandboxes \
  -H "X-API-Key: $RUNTOOLS_API_KEY"
```

The SDK reads `RUNTOOLS_API_KEY` automatically:

```typescript theme={null}
import { RunTools } from '@runtools-ai/sdk';

const rt = new RunTools();
const sandboxes = await rt.sandbox.list();
```

Or pass a key explicitly:

```typescript theme={null}
const rt = new RunTools({
  apiKey: process.env.RUNTOOLS_API_KEY,
});
```

## Session Tokens

Dashboard and CLI login use WorkOS-backed session tokens. Session tokens authenticate with `Authorization: Bearer`:

```bash theme={null}
curl https://api.runtools.ai/v1/me \
  -H "Authorization: Bearer $RUNTOOLS_ACCESS_TOKEN"
```

The CLI manages those tokens for you:

```bash theme={null}
runtools login
runtools auth status
runtools logout
```

## Environment Variables

```bash .env theme={null}
RUNTOOLS_API_KEY=rt_live_xxx

# Optional service overrides for local development
RUNTOOLS_API_URL=https://api.runtools.ai
RUNTOOLS_AUTH_URL=https://auth.runtools.ai
RUNTOOLS_TOOLS_URL=https://tools.runtools.ai
RUNTOOLS_BILLING_URL=https://billing.runtools.ai
```

## Scopes

API key scopes are checked by the API service. Use the narrowest scopes that fit your integration.

| Scope           | Access                                                  |
| --------------- | ------------------------------------------------------- |
| `*`             | Full API key access for the organization                |
| `sandbox:*`     | Sandbox lifecycle and command execution                 |
| `agent:*`       | Agent management and runs                               |
| `agent:run`     | Run agents                                              |
| `files:read`    | Read workspace metadata and files                       |
| `files:write`   | Create, update, and delete workspace metadata and files |
| `activity:read` | Read customer-visible activity events                   |
| `runmesh:read`  | Read RunMesh nodes, configs, audit, and status          |
| `runmesh:write` | Approve, rename, or revoke RunMesh devices              |
| `tool:*`        | Tool Hub installs, credentials, and execution           |
| `ssh-key:*`     | SSH key management                                      |

<Warning>
  API keys are shown once at creation. Store them in a secret manager or environment variable, not in source code.
</Warning>

## Rotation

1. Create a replacement key.
2. Deploy the new key to your application or CI secret store.
3. Verify the new key works.
4. Revoke the old key.

```bash theme={null}
runtools auth keys create "production-2026-05" --scope "*"
runtools auth keys revoke <old-key-id>
```

## Errors

Authentication failures use normal API error envelopes:

```json theme={null}
{
  "error": {
    "code": "unauthorized",
    "message": "Invalid or missing authentication"
  }
}
```

If a request works in the dashboard but fails with an API key, check the key scopes and the organization selected when the key was created.
