Skip to content

Device Code Flow

The Device Code flow enables authentication in environments without direct browser access.

Overview

This flow is designed for:

  • Remote servers without a GUI
  • Docker containers
  • SSH sessions
  • IoT devices

The user authenticates on a separate device (like a phone or laptop) while the application polls for completion.

sequenceDiagram
    participant App as Application
    participant IdP as Identity Provider
    participant User
    participant Browser as User's Browser

    App->>IdP: Request device code
    IdP->>App: Device code + User code + URL
    App->>User: Display code and URL
    User->>Browser: Navigate to URL
    User->>Browser: Enter user code
    User->>Browser: Authenticate

    loop Polling
        App->>IdP: Check authorization status
        IdP->>App: Pending / Success / Error
    end

    IdP->>App: Access + Refresh tokens

Step 1: Request Device Code

Request a device code from the identity provider:

curl --request POST \
  --url "https://{auth_base_url}/oauth/device/code" \
  --header "content-type: application/x-www-form-urlencoded" \
  --data "client_id={client_id}" \
  --data "scope=openid email profile offline_access" \
  --data "audience={audience}"

Response:

{
  "device_code": "Ag_EE...ko1p",
  "user_code": "QTZL-MCBW",
  "verification_uri": "https://quera-identity.us.auth0.com/activate",
  "verification_uri_complete": "https://quera-identity.us.auth0.com/activate?user_code=QTZL-MCBW",
  "expires_in": 900,
  "interval": 5
}
Field Description
device_code Code used for polling (keep secret)
user_code Code displayed to user
verification_uri URL where user enters the code
verification_uri_complete URL with code pre-filled
expires_in Seconds until codes expire
interval Minimum seconds between poll requests

Step 2: Display Instructions to User

Show the user:

To authenticate, please:
1. Open: https://quera-identity.us.auth0.com/activate
2. Enter code: QTZL-MCBW
3. Follow the login prompts

Waiting for authentication...

Or provide the complete URL for easier access.

Step 3: Poll for Completion

Poll the token endpoint at the specified interval:

curl --request POST \
  --url "https://{auth_base_url}/oauth/token" \
  --header "content-type: application/x-www-form-urlencoded" \
  --data grant_type=urn:ietf:params:oauth:grant-type:device_code \
  --data "device_code={device_code}" \
  --data "client_id={client_id}"

Polling Responses

Still waiting:

{
  "error": "authorization_pending",
  "error_description": "User has yet to authorize device code."
}

Continue polling.

Too fast:

{
  "error": "slow_down",
  "error_description": "You are polling faster than the specified interval."
}

Increase polling interval and continue.

Success:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 86400,
  "refresh_token": "v1.MSjO...",
  "scope": "openid profile email offline_access"
}

Expired:

{
  "error": "expired_token",
  "error_description": "The device code has expired."
}

Start over from Step 1.

Denied:

{
  "error": "access_denied",
  "error_description": "User denied access."
}

User explicitly denied authorization.

Next Steps