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

# Poll for a device login token

RFC 8628 device access token request. Until the user approves, answers `400` with `authorization_pending` (or `slow_down` when you poll faster than `interval`: add 5 seconds to it). After approval returns a `b3os_pat_` token once; the device code then stops working. Errors use the OAuth shape `{error, error_description}`; too many polls from one address get `429` with `error: rate_limited`. 

` POST /v1/auth/device/token `

Poll for a device login token

RFC 8628 device access token request. Until the user approves, answers `400` with `authorization_pending`
(or `slow_down` when you poll faster than `interval`: add 5 seconds to it). After approval returns a
`b3os_pat_` token once; the device code then stops working. Errors use the OAuth shape
`{error, error_description}`; too many polls from one address get `429` with `error: rate_limited`.


## Servers

- ` https://beta-api.b3os.org ` — API (API keys and CLI tokens)

- ` https://beta.b3os.org ` — Dashboard (session cookie and CSRF header; same paths)

## Request body (required)

Content type: ` application/json `

- ` value `: type ` object `

  - Required fields: ` grant_type `, ` device_code `, ` client_id `

  - ` grant_type `: type ` string `

    - enum: ` ["urn:ietf:params:oauth:grant-type:device_code"] `

  - ` device_code `: type ` string `

    - maxLength: ` 256 `

  - ` client_id `: type ` string `

    - maxLength: ` 64 `

Example:

```json
{
  "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
  "device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
  "client_id": "b3os-cli"
}
```

## Responses

### ` 200 ` — The token.

Content type: ` application/json `

- ` value `: type ` object ` — RFC 6749 §5.1 token response, plus the organization and project the token acts in.

  - Required fields: ` access_token `, ` token_type `, ` expires_in `, ` scope `, ` org_id `, ` project_id `

  - ` access_token `: type ` string `

    - pattern: ` "^b3os_pat_[a-z2-7]{32}_[0-9a-f]{8}$" `

  - ` token_type `: type ` string `

    - enum: ` ["Bearer"] `

  - ` expires_in `: type ` integer `

  - ` scope `: type ` string `

  - ` org_id `: type ` string `

  - ` project_id `: type ` string `

Response header ` x-request-id ` — The request ID (`req_…`). It is the `instance` of any problem and the key for `GET /v1/requests/{request_id}`.

- ` value `: type ` string `

  - pattern: ` "^req_[0-9a-hjkmnp-tv-z]{26}$" `

Response header ` Server-Timing ` — Phase durations in milliseconds (W3C Server Timing); the handler's phases break the request down. For a
response whose body size is known, `total` runs from reading the request head to writing the response head.
Streaming responses (event streams, WebSockets, chunked bodies) carry no `total` here: they report their
final phases in the terminal event (`job.succeeded`, `job.failed`, `job.canceled`) or the final job. The
time from the first request byte to the last response byte is recorded in the node's metrics and request
log (`GET /v1/requests/{request_id}`). The edge prepends `edge_auth` and `edge_upstream`.


- ` value `: type ` string `

Example:

```json
{
  "access_token": "b3os_pat_ex4mple7ex4mple7ex4mple7ex4mple7_13cd7b34",
  "token_type": "Bearer",
  "expires_in": 7776000,
  "scope": "*",
  "org_id": "org_01m5t5hthd29mm5wpza5ndd6mm",
  "project_id": "prj_01m5t3pf8heewxt65ej3dm577y"
}
```

### ` 400 ` — Not approved yet, polling too fast, denied, expired or already used (`authorization_pending`, `slow_down`, `access_denied`, `expired_token`, `invalid_grant`).

Content type: ` application/json `

- ` value `: type ` object ` — RFC 6749 §5.2 error response. `error` is an errors.yaml code: the RFC 6749 and RFC 8628 codes, plus `rate_limited` (429) for too many device logins from one address. 

  - Required fields: ` error `

  - ` error `: type ` string `

    - enum: ` ["invalid_request","invalid_client","invalid_grant","unsupported_grant_type","authorization_pending","slow_down","access_denied","expired_token","rate_limited"] `

  - ` error_description `: type ` string `

Response header ` x-request-id ` — The request ID (`req_…`). It is the `instance` of any problem and the key for `GET /v1/requests/{request_id}`.

- ` value `: type ` string `

  - pattern: ` "^req_[0-9a-hjkmnp-tv-z]{26}$" `

Response header ` Server-Timing ` — Phase durations in milliseconds (W3C Server Timing); the handler's phases break the request down. For a
response whose body size is known, `total` runs from reading the request head to writing the response head.
Streaming responses (event streams, WebSockets, chunked bodies) carry no `total` here: they report their
final phases in the terminal event (`job.succeeded`, `job.failed`, `job.canceled`) or the final job. The
time from the first request byte to the last response byte is recorded in the node's metrics and request
log (`GET /v1/requests/{request_id}`). The edge prepends `edge_auth` and `edge_upstream`.


- ` value `: type ` string `

Example:

```json
{
  "error": "authorization_pending",
  "error_description": "The user has not approved this device yet"
}
```

### ` 401 ` — Unknown client (`invalid_client`).

Content type: ` application/json `

- ` value `: type ` object ` — RFC 6749 §5.2 error response. `error` is an errors.yaml code: the RFC 6749 and RFC 8628 codes, plus `rate_limited` (429) for too many device logins from one address. 

  - Required fields: ` error `

  - ` error `: type ` string `

    - enum: ` ["invalid_request","invalid_client","invalid_grant","unsupported_grant_type","authorization_pending","slow_down","access_denied","expired_token","rate_limited"] `

  - ` error_description `: type ` string `

Response header ` x-request-id ` — The request ID (`req_…`). It is the `instance` of any problem and the key for `GET /v1/requests/{request_id}`.

- ` value `: type ` string `

  - pattern: ` "^req_[0-9a-hjkmnp-tv-z]{26}$" `

Response header ` Server-Timing ` — Phase durations in milliseconds (W3C Server Timing); the handler's phases break the request down. For a
response whose body size is known, `total` runs from reading the request head to writing the response head.
Streaming responses (event streams, WebSockets, chunked bodies) carry no `total` here: they report their
final phases in the terminal event (`job.succeeded`, `job.failed`, `job.canceled`) or the final job. The
time from the first request byte to the last response byte is recorded in the node's metrics and request
log (`GET /v1/requests/{request_id}`). The edge prepends `edge_auth` and `edge_upstream`.


- ` value `: type ` string `

Example:

```json
{
  "error": "invalid_client",
  "error_description": "Unknown client_id b3os-cli2"
}
```

### ` 429 ` — Too many device logins from this address (`rate_limited`, in the OAuth error shape). Wait `Retry-After`
seconds. Polling the token endpoint faster than `interval` is `slow_down` (400), not this.


Content type: ` application/json `

- ` value `: type ` object ` — RFC 6749 §5.2 error response. `error` is an errors.yaml code: the RFC 6749 and RFC 8628 codes, plus `rate_limited` (429) for too many device logins from one address. 

  - Required fields: ` error `

  - ` error `: type ` string `

    - enum: ` ["invalid_request","invalid_client","invalid_grant","unsupported_grant_type","authorization_pending","slow_down","access_denied","expired_token","rate_limited"] `

  - ` error_description `: type ` string `

Response header ` x-request-id ` — The request ID (`req_…`). It is the `instance` of any problem and the key for `GET /v1/requests/{request_id}`.

- ` value `: type ` string `

  - pattern: ` "^req_[0-9a-hjkmnp-tv-z]{26}$" `

Response header ` Server-Timing ` — Phase durations in milliseconds (W3C Server Timing); the handler's phases break the request down. For a
response whose body size is known, `total` runs from reading the request head to writing the response head.
Streaming responses (event streams, WebSockets, chunked bodies) carry no `total` here: they report their
final phases in the terminal event (`job.succeeded`, `job.failed`, `job.canceled`) or the final job. The
time from the first request byte to the last response byte is recorded in the node's metrics and request
log (`GET /v1/requests/{request_id}`). The edge prepends `edge_auth` and `edge_upstream`.


- ` value `: type ` string `

Response header ` Retry-After ` — Seconds to wait before retrying or polling again.

- ` value `: type ` integer `

  - minimum: ` 0 `

Example:

```json
{
  "error": "rate_limited",
  "error_description": "Too many device logins from this address; retry after 30 seconds"
}
```

## Request examples

### cURL

```curl
curl -X POST 'https://beta-api.b3os.org/v1/auth/device/token' \
  -H 'Authorization: Bearer YOUR_API_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
  "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
  "device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
  "client_id": "b3os-cli"
}'
```

### JavaScript

```javascript
const response = await fetch('https://beta-api.b3os.org/v1/auth/device/token', {
  method: 'POST',
  headers: {
      "Authorization": "Bearer YOUR_API_TOKEN",
      "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
    "device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
    "client_id": "b3os-cli"
  })
});

const data = await response.json();
console.log(data);
```

### Python

```python
import requests

headers = {
    'Authorization': 'Bearer YOUR_API_TOKEN'
}

response = requests.post('https://beta-api.b3os.org/v1/auth/device/token', headers=headers, json={
  "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
  "device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
  "client_id": "b3os-cli"
})
print(response.json())
```