Skip to main content
Request a device code for OAuth device flow authentication (primarily for CLI).

Request

Method: POST Endpoint: /oauth/device/authorize
curl -X POST "https://api.noorle.com/oauth/device/authorize" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "noorle-cli",
    "scope": "api"
  }'

Request Body

{
  "client_id": "noorle-cli",
  "scope": "api"
}
FieldTypeRequiredDescription
client_idstringYesOAuth client ID (e.g., “noorle-cli”)
scopestringNoSpace-separated scopes (default: “api”)

Response

{
  "device_code": "ABCD1234EFGH5678",
  "user_code": "WXYZ1234",
  "verification_uri": "https://console.noorle.com/oauth/device/verify",
  "expires_in": 1800,
  "interval": 5
}
FieldTypeDescription
device_codestringCode for polling token endpoint
user_codestringCode user enters at verification_uri
verification_uristringURL where user approves request
expires_inintegerSeconds until codes expire (typically 30 minutes)
intervalintegerMinimum seconds between polling (typically 5)

Flow

  1. Request device code
    curl -X POST https://api.noorle.com/oauth/device/authorize \
      -H "Content-Type: application/json" \
      -d '{"client_id": "noorle-cli"}'
    
  2. Display user code and verification URI
    Please visit: https://console.noorle.com/oauth/device/verify
    And enter code: WXYZ1234
    
  3. User approves in browser
  4. Poll for token (see oauth/token)
    curl -X POST https://api.noorle.com/oauth/token \
      -H "Content-Type: application/json" \
      -d '{
        "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
        "device_code": "ABCD1234EFGH5678",
        "client_id": "noorle-cli"
      }'
    

Example: CLI Flow

#!/bin/bash

# Step 1: Request device code
RESPONSE=$(curl -s -X POST https://api.noorle.com/oauth/device/authorize \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "noorle-cli",
    "scope": "api"
  }')

DEVICE_CODE=$(echo $RESPONSE | jq -r '.device_code')
USER_CODE=$(echo $RESPONSE | jq -r '.user_code')
VERIFY_URI=$(echo $RESPONSE | jq -r '.verification_uri')
INTERVAL=$(echo $RESPONSE | jq -r '.interval')

# Step 2: Display verification instructions
echo "Please visit: $VERIFY_URI"
echo "Enter code: $USER_CODE"

# Step 3: Poll for token
while true; do
  TOKEN_RESPONSE=$(curl -s -X POST https://api.noorle.com/oauth/token \
    -H "Content-Type: application/json" \
    -d "{
      \"grant_type\": \"urn:ietf:params:oauth:grant-type:device_code\",
      \"device_code\": \"$DEVICE_CODE\",
      \"client_id\": \"noorle-cli\"
    }")

  # Check for token
  if echo $TOKEN_RESPONSE | jq -e '.access_token' >/dev/null 2>&1; then
    ACCESS_TOKEN=$(echo $TOKEN_RESPONSE | jq -r '.access_token')
    echo "✓ Authenticated!"
    echo $ACCESS_TOKEN > ~/.noorle/token
    break
  fi

  # Check for error
  if echo $TOKEN_RESPONSE | jq -e '.error' >/dev/null 2>&1; then
    ERROR=$(echo $TOKEN_RESPONSE | jq -r '.error')
    if [ "$ERROR" == "authorization_pending" ]; then
      echo "Waiting for approval..."
    elif [ "$ERROR" == "slow_down" ]; then
      INTERVAL=$((INTERVAL + 5))
    else
      echo "Error: $ERROR"
      exit 1
    fi
  fi

  sleep $INTERVAL
done

Status Codes

CodeMeaning
200Success, codes generated
400Invalid client_id or scope
429Rate limited

Errors

Invalid Client

{
  "error": "invalid_client",
  "error_description": "Unknown client: invalid-id"
}

Invalid Scope

{
  "error": "invalid_scope",
  "error_description": "Scope 'unknown' is not supported"
}

Device Code Lifetime

  • Default expiry: 30 minutes (1800 seconds)
  • After expiry: Codes become invalid, must request new ones
  • User approval window: Must approve within expiry period

Polling Strategy

After requesting device code:
  1. Minimum interval: Wait interval seconds between polls (typically 5)
  2. Exponential backoff: If server sends slow_down, increase interval by 5 seconds
  3. Timeout: Stop polling after expires_in seconds

Next Steps