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

# Device authorization

> Reference for the OAuth 2.0 device authorization grant flow used by the CLI, including endpoints, timing, and security notes.

## Device authorization reference

This section provides detailed technical information about the OAuth 2.0 Device Authorization Grant flow used by the CLI.

### Overview

The device flow lets a CLI request authorization while the user completes login in a browser on a secondary device. Nscale follows RFC 8628.

```mermaid theme={null}
sequenceDiagram
  participant CLI as CLI (Device)
  participant API as Console API
  participant Browser as Browser (User)

  CLI->>API: POST /api/oauth2/device<br/>{ client_id, scope }
  API-->>CLI: { device_code, user_code,<br/>verification_uri,<br/>expires_in: 600,<br/>interval: 5 }
  CLI->>Browser: Display verification URI<br/>and user code
  Browser->>API: GET /auth/device?code=XXXX-YYYY
  Browser->>API: POST /api/auth/device/verify<br/>{ code }
  API-->>Browser: { valid: true, scope }
  Browser->>API: GET /auth/device/callback
  Note over API: authorizeDevice() stores tokens<br/>in secure session store
  loop Poll until authorized
    CLI->>API: POST /api/oauth2/token<br/>{ grant_type: device_code,<br/>device_code, client_id }
    API-->>CLI: authorization_pending / slow_down
  end
  API-->>CLI: { access_token, refresh_token,<br/>token_type: "Bearer", expires_in }
```

### Technical details

#### Session storage

Device sessions are stored in a secure, server-side key-value store. Sessions are never exposed to the client and are automatically expired.

#### Timing

| Parameter           | Value                | Description                                        |
| ------------------- | -------------------- | -------------------------------------------------- |
| Session TTL         | 600 seconds (10 min) | Time for user to complete authentication           |
| Token pickup window | 60 seconds           | Time for CLI to retrieve token after authorization |
| Polling interval    | 5 seconds            | Minimum interval between polling requests          |

#### User codes

User codes are 8 characters in format `XXXX-YYYY` and use an ambiguity-reduced character set to minimize input errors.

### API endpoints

#### 1. Device authorization request

**`POST /api/oauth2/device`**

Initiates the device authorization flow.

Request:

```bash theme={null}
curl -X POST https://console.nscale.com/api/oauth2/device \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=<CLI_CLIENT_ID>&scope=openid%20profile%20email"
```

Response:

```json theme={null}
{
  "device_code": "550e8400-e29b-41d4-a716-446655440000",
  "user_code": "WDJB-MJHT",
  "verification_uri": "https://console.nscale.com/auth/device",
  "verification_uri_complete": "https://console.nscale.com/auth/device?code=WDJB-MJHT",
  "expires_in": 600,
  "interval": 5
}
```

#### 2. Token endpoint (polling)

**`POST /api/oauth2/token`**

The CLI polls this endpoint until authorization completes.

Request:

```bash theme={null}
curl -X POST https://console.nscale.com/api/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
  -d "device_code=550e8400-e29b-41d4-a716-446655440000" \
  -d "client_id=<CLI_CLIENT_ID>"
```

Responses:

| Status | Error code              | Meaning                     | Action                         |
| ------ | ----------------------- | --------------------------- | ------------------------------ |
| 400    | `authorization_pending` | User has not completed auth | Wait `interval` seconds, retry |
| 400    | `slow_down`             | Polling too fast            | Increase interval, retry       |
| 400    | `access_denied`         | User denied request         | Stop polling, show error       |
| 400    | `expired_token`         | Session expired             | Stop polling, restart flow     |
| 200    | -                       | Success                     | Use returned tokens            |

Success response:

```json theme={null}
{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "refresh_token": "eyJ...",
  "expires_in": 3599
}
```

#### 3. Token refresh

**`POST /api/oauth2/token`**

Refresh an expired access token.

Request:

```bash theme={null}
curl -X POST https://console.nscale.com/api/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=<REFRESH_TOKEN>"
```

### Token storage recommendations

Store tokens securely using platform-appropriate mechanisms:

| Platform | Recommended storage                                   |
| -------- | ----------------------------------------------------- |
| macOS    | Keychain (`security` command or `keytar` npm package) |
| Linux    | libsecret / GNOME Keyring / encrypted file            |
| Windows  | Windows Credential Manager                            |

Example with keytar:

```typescript theme={null}
import * as keytar from "keytar";

const SERVICE_NAME = "nscale-cli";
const ACCOUNT_NAME = "default";

async function storeTokens(tokens: TokenResponse): Promise<void> {
  await keytar.setPassword(
    SERVICE_NAME,
    ACCOUNT_NAME,
    JSON.stringify({
      access_token: tokens.access_token,
      refresh_token: tokens.refresh_token,
      expires_at: Date.now() + (tokens.expires_in || 3600) * 1000,
    })
  );
}
```

### Security considerations

#### Device code phishing

Attackers can socially engineer users into authorizing malicious device codes. Mitigations include:

* Short session TTL (10 minutes) limits attack window.
* User sees a consent screen with requested scopes.
* Users can deny suspicious requests.
* Device flow can be disabled if not required.

#### Brute force code guessing

Mitigations include high-entropy user codes, short TTLs, and consistent error responses to prevent enumeration.

#### Token leakage

Mitigations include single-use tokens, short pickup windows (60 seconds), and secure server-side session storage.

#### Polling rate abuse

Mitigations include server-side rate limiting and the `slow_down` error when polling too fast.

### RFC 8628 compliance

Our implementation follows RFC 8628 (OAuth 2.0 Device Authorization Grant):

| Requirement                            | Status | Implementation                      |
| -------------------------------------- | ------ | ----------------------------------- |
| Device authorization endpoint          | Yes    | `POST /api/oauth2/device`           |
| Token endpoint with device\_code grant | Yes    | `POST /api/oauth2/token`            |
| User code display                      | Yes    | 8-character code format `XXXX-YYYY` |
| Verification URI                       | Yes    | `/auth/device`                      |
| Verification URI complete              | Yes    | `/auth/device?code={user_code}`     |
| expires\_in parameter                  | Yes    | 600 seconds                         |
| interval parameter                     | Yes    | 5 seconds                           |
| authorization\_pending error           | Yes    | Returned while user authenticating  |
| slow\_down error                       | Yes    | Returned when polling too fast      |
| access\_denied error                   | Yes    | Returned when user denies           |
| expired\_token error                   | Yes    | Returned when session expires       |

### References

* [RFC 8628 - OAuth 2.0 Device Authorization Grant](https://datatracker.ietf.org/doc/html/rfc8628)
