# Authentication (/docs/api/authentication)



Every API request authenticates with a CrowNest bearer credential sent in
the `Authorization` header. Developer API keys and auth.md agent access
tokens use the same runtime scope vocabulary, but they are separate
credential types with separate lifecycle, audit, and revocation controls.

We recommend that agents use the auth.md flow rather than asking users to
paste raw developer API keys. The API advertises auth.md discovery on unauthenticated
responses with a `WWW-Authenticate` header that points to protected
resource metadata.

## API keys [#api-keys]

API keys are developer-managed organization credentials. They are useful
for local development, CI, and server-side automation controlled directly
by your team.

Pass your key in the `Authorization` header on every request:

```bash title="Terminal"
curl https://api.crownest.dev/v1/sandboxes \
  -H "Authorization: Bearer $CROWNEST_API_KEY"
```

Keys look like `cn_live_...`. The raw value is shown exactly once, at
creation time — CrowNest stores only the key prefix, a hash, and the last
four characters, so you can't retrieve a key again later. Store it in a
secret manager or an environment variable such as `CROWNEST_API_KEY`.

You create API keys in the dashboard. Programmatic key creation is not
available. Automation can list, inspect, and revoke keys only from an
org-wide key that explicitly has the `api_key:read` and `api_key:revoke`
scopes.

## auth.md agent credentials [#authmd-agent-credentials]

CrowNest serves agent registration metadata at:

* `https://api.crownest.dev/auth.md`
* `https://api.crownest.dev/.well-known/oauth-protected-resource`
* `https://api.crownest.dev/.well-known/oauth-authorization-server`

The supported protocol endpoints are:

| Endpoint                     | Purpose                                                                    |
| ---------------------------- | -------------------------------------------------------------------------- |
| `POST /agent/identity`       | Start `service_auth`, `anonymous`, or provider identity registration.      |
| `POST /agent/identity/claim` | Start a human claim for an anonymous registration.                         |
| `GET /agent/bootstrap`       | Read public bootstrap metadata with a pre-claim token.                     |
| `POST /oauth2/token`         | Exchange a claim token or CrowNest identity assertion for an access token. |
| `POST /oauth2/revoke`        | Revoke one agent access token.                                             |
| `POST /agent/event/notify`   | Receive trusted provider security events.                                  |

Agent access tokens look like `cn_agent_...`, expire quickly, and are
stored only as hashes. A user completes claim approval at
`https://crownest.dev/agent/identity/claim` through WorkOS/AuthKit. Owner
or admin approval is required for developer runtime scopes such as
`sandbox:create`; non-admin claim participants can only complete constrained
flows.

Use `CROWNEST_BEARER_TOKEN` for SDK and CLI examples that may receive
either an agent token or a developer API key. `CROWNEST_API_KEY` remains a
backward-compatible alias for developer API keys.

## Scopes [#scopes]

Each scope is a singular `resource:action` string, such as
`sandbox:create`. A key can only call endpoints whose required scope it
holds. Every endpoint in this reference lists its required scope.

| Scope                  | Allows                                          |
| ---------------------- | ----------------------------------------------- |
| `sandbox:create`       | Create sandboxes                                |
| `sandbox:read`         | List and get sandboxes                          |
| `sandbox:kill`         | Delete (kill) sandboxes                         |
| `sandbox:extend`       | Set sandbox TTL                                 |
| `command:run`          | Run foreground and background commands          |
| `command:read`         | Get commands, read logs, stream logs            |
| `command:cancel`       | Cancel commands                                 |
| `workspace_run:create` | Create, upload, and start Workspace Runs        |
| `workspace_run:read`   | Read Workspace Run status, events, and evidence |
| `workspace_run:cancel` | Cancel active Workspace Runs                    |
| `backup:create`        | Beta / feature-gated backup creation            |
| `backup:read`          | Beta / feature-gated backup metadata reads      |
| `backup:restore`       | Beta / feature-gated sandbox restore            |
| `backup:delete`        | Beta / feature-gated backup deletion            |
| `code:run`             | Create, list, get, delete contexts; run code    |
| `file:read`            | List, stat, read, and download workspace files  |
| `file:write`           | Write, move, delete files, create directories   |
| `artifact:create`      | Export artifacts from a sandbox                 |
| `artifact:read`        | List, get, and download artifacts               |
| `artifact:delete`      | Delete artifacts                                |
| `preview:create`       | Create previews                                 |
| `preview:read`         | List and get previews                           |
| `preview:revoke`       | Revoke previews                                 |
| `usage:read`           | Read usage and quota information                |
| `api_key:read`         | List and inspect API key metadata               |
| `api_key:revoke`       | Revoke API keys                                 |
| `project:create`       | Create projects with an org-wide key            |

The dashboard offers scope presets when you create a key:

* **Quickstart Developer** — full sandbox, command, code, file, artifact,
  Workspace Run, and preview management, plus `usage:read`. Use this for
  development.
* **Project Runtime** — runtime scopes without the destructive
  `artifact:delete` and `preview:revoke`. Use this for production
  workloads.
* **Read Only** — `sandbox:read`, `command:read`, `file:read`,
  `artifact:read`, `workspace_run:read`, `preview:read`, and `usage:read`.
  Use this for monitoring and dashboards.

Backup scopes are advertised for compatibility with beta accounts. Agents
should treat `backup:create`, `backup:read`, `backup:restore`, and
`backup:delete` as feature-gated until the API returns backup operations in
the account's normal capability surface.

## API key management endpoints [#api-key-management-endpoints]

Key creation is dashboard-only. Existing org-wide API keys can read and
revoke key metadata through these endpoints when granted the matching
scopes:

| Endpoint                   | Scope            | Description             |
| -------------------------- | ---------------- | ----------------------- |
| `GET /v1/api-keys`         | `api_key:read`   | List API key metadata.  |
| `GET /v1/api-keys/{id}`    | `api_key:read`   | Get one API key record. |
| `DELETE /v1/api-keys/{id}` | `api_key:revoke` | Revoke an API key.      |

## Project-restricted keys [#project-restricted-keys]

Keys are org-scoped by default and can reach every project in the
organization. You can restrict a key to one or more projects when you
create it in the dashboard. A project-restricted key can only see and act
on resources in its allowed projects; resources elsewhere return
`not_found` or `forbidden`. Project-restricted keys cannot use API-key
management scopes; listing, reading, and revoking keys requires an
org-wide key.

## 401 vs 403 [#401-vs-403]

The API distinguishes between authentication and authorization failures:

* **401** — the request isn't authenticated. The key is missing, malformed,
  invalid, expired, or revoked. Error codes include `unauthorized`,
  `invalid_api_key`, and `agent_token_expired`. Fix or refresh the
  credential. 401 responses include auth.md discovery metadata when the
  route supports agent registration.
* **403** — the request is authenticated, but the key lacks the required
  scope or has no access to the resource. Error code: `forbidden`. Fix the
  key's scopes or project restrictions.

## Next steps [#next-steps]

* Set up agent registration in [auth.md for agents](/docs/agents/auth-md).
* Learn the error envelope in [Errors](/docs/api/errors).
* Create a sandbox in [Sandboxes](/docs/api/sandboxes).
