Skip to main content

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.

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

ParameterValueDescription
Session TTL600 seconds (10 min)Time for user to complete authentication
Token pickup window60 secondsTime for CLI to retrieve token after authorization
Polling interval5 secondsMinimum 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:
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:
{
  "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:
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:
StatusError codeMeaningAction
400authorization_pendingUser has not completed authWait interval seconds, retry
400slow_downPolling too fastIncrease interval, retry
400access_deniedUser denied requestStop polling, show error
400expired_tokenSession expiredStop polling, restart flow
200-SuccessUse returned tokens
Success response:
{
  "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:
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:
PlatformRecommended storage
macOSKeychain (security command or keytar npm package)
Linuxlibsecret / GNOME Keyring / encrypted file
WindowsWindows Credential Manager
Example with keytar:
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):
RequirementStatusImplementation
Device authorization endpointYesPOST /api/oauth2/device
Token endpoint with device_code grantYesPOST /api/oauth2/token
User code displayYes8-character code format XXXX-YYYY
Verification URIYes/auth/device
Verification URI completeYes/auth/device?code={user_code}
expires_in parameterYes600 seconds
interval parameterYes5 seconds
authorization_pending errorYesReturned while user authenticating
slow_down errorYesReturned when polling too fast
access_denied errorYesReturned when user denies
expired_token errorYesReturned when session expires

References