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

# OAuth device flow

> Use SiteGPT OAuth device authorization to let a CLI or AI agent obtain a scoped SiteGPT API token.

SiteGPT supports OAuth Device Authorization Grant for local CLIs, scripts, and personal AI agents. This is the protocol used by `sitegpt login`.

Use this page when you are building an agent or integration that wants to authenticate without asking the user to copy a token manually.

<Note>
  Most users should run `sitegpt login` instead of calling these endpoints directly. The CLI handles device authorization, polling, profile storage, and API token use.
</Note>

## Discovery

Agents can discover SiteGPT's OAuth device flow from the authorization-server metadata:

```bash theme={null}
curl https://sitegpt.ai/.well-known/oauth-authorization-server
```

The protected API resource metadata is available at:

```bash theme={null}
curl https://sitegpt.ai/.well-known/oauth-protected-resource
curl https://sitegpt.ai/.well-known/oauth-protected-resource/api/v2
```

The API resource is:

```text theme={null}
https://sitegpt.ai/api/v2
```

## Client ID

Use this client ID for the first-party SiteGPT CLI/device flow:

```text theme={null}
sitegpt-cli
```

`client_id` identifies the application requesting access. It is not a secret and does not identify the user. All users of the SiteGPT CLI use the same `client_id`.

## Start device authorization

Send a form-encoded request to `/oauth/device_authorization`:

```bash theme={null}
curl -s -X POST https://sitegpt.ai/oauth/device_authorization \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=sitegpt-cli" \
  -d "token_name=SiteGPT CLI" \
  -d "scope=account:read chatbots:read knowledge:write"
```

Response:

```json theme={null}
{
  "device_code": "sgpt_device_...",
  "user_code": "ABCD-EFGH",
  "verification_uri": "https://sitegpt.ai/device",
  "verification_uri_complete": "https://sitegpt.ai/device?user_code=ABCD-EFGH",
  "expires_in": 899,
  "interval": 2
}
```

Open `verification_uri_complete` in a browser. The signed-in SiteGPT user reviews the requested access and approves or denies the request.

## Poll for the token

Poll `/oauth/token` with the device code:

```bash theme={null}
curl -s -X POST https://sitegpt.ai/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
  -d "client_id=sitegpt-cli" \
  -d "device_code=<device_code>"
```

Before approval, SiteGPT returns:

```json theme={null}
{
  "error": "authorization_pending",
  "error_description": "Device login is pending approval.",
  "interval": 2
}
```

Respect the `interval` before polling again. If you poll too quickly, SiteGPT can return:

```json theme={null}
{
  "error": "slow_down",
  "error_description": "Poll interval is too short. Wait before polling again.",
  "interval": 7
}
```

After approval, SiteGPT returns a scoped bearer token:

```json theme={null}
{
  "access_token": "sgpt_xxxxxxxxx",
  "token_type": "Bearer",
  "expires_in": 7775999,
  "scope": "account:read chatbots:read knowledge:write",
  "sitegpt_token": {
    "id": "token-id",
    "name": "SiteGPT CLI",
    "tokenPrefix": "xxxxxxxxx",
    "scopes": ["account:read", "chatbots:read", "knowledge:write"],
    "chatbotIds": [],
    "expiresAt": "2026-08-11T00:00:00.000Z"
  }
}
```

Use `access_token` as the bearer token for `/api/v2` requests:

```bash theme={null}
curl https://sitegpt.ai/api/v2/me \
  -H "Authorization: Bearer sgpt_xxxxxxxxx"
```

## Request fields

### `/oauth/device_authorization`

| Field             | Required | Description                                                                                                                                      |
| ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `client_id`       | Yes      | Use `sitegpt-cli` for the first-party SiteGPT CLI/device flow.                                                                                   |
| `scope`           | No       | Space-separated SiteGPT scopes. If omitted, SiteGPT requests standard CLI access. See [available scopes](/cli/authentication#available-scopes).  |
| `full_access`     | No       | Default: `false`. Set to `true` to request all self-service scopes the approving user's dashboard role can issue. Do not send this with `scope`. |
| `token_name`      | No       | Token name shown in the dashboard.                                                                                                               |
| `name`            | No       | Alias for `token_name`.                                                                                                                          |
| `expires_in_days` | No       | Token lifetime in days. Valid range: `1-365`. Default: `90`.                                                                                     |
| `chatbot_id`      | No       | Restrict access to one chatbot. Repeat for multiple chatbots.                                                                                    |
| `chatbot_ids`     | No       | Comma-separated chatbot IDs.                                                                                                                     |

### `/oauth/token`

| Field         | Required | Description                                                                                 |
| ------------- | -------- | ------------------------------------------------------------------------------------------- |
| `grant_type`  | Yes      | Must be `urn:ietf:params:oauth:grant-type:device_code`.                                     |
| `client_id`   | Yes      | Use the same client ID used to start authorization. For the SiteGPT CLI, use `sitegpt-cli`. |
| `device_code` | Yes      | The `device_code` returned by `/oauth/device_authorization`.                                |

## Error responses

| Error                   | Meaning                                                                |
| ----------------------- | ---------------------------------------------------------------------- |
| `authorization_pending` | The user has not approved the browser prompt yet. Wait and poll again. |
| `slow_down`             | The client is polling too quickly. Increase the polling interval.      |
| `access_denied`         | The user denied the request. Stop polling.                             |
| `expired_token`         | The device code expired. Start a new login.                            |
| `invalid_grant`         | The device code is invalid, consumed, or no longer usable.             |
| `invalid_scope`         | One or more requested scopes are not valid or not self-service.        |
| `invalid_request`       | Required fields are missing or malformed.                              |

## Security notes

* Do not put `access_token` in prompts, shared chats, source code, or logs.
* Use the smallest scope set needed for the agent.
* Use `chatbot_id` restrictions for chatbot-specific agents.
* Rotate or revoke tokens after demos and shared sessions.
* For normal CLI usage, prefer `sitegpt login`; it stores the token in a local profile.
