Skip to Content
GuidesAuthenticationDevice Authorization Flow

Device Authorization Flow

The Device Authorization Grant (RFC 8628) allows users to log in on devices that have limited or no browser capabilities. Instead of entering credentials directly on the device, the user is shown a short code and a URL. They visit the URL on a phone or laptop, enter the code, and approve the request. Meanwhile, the device polls the token endpoint until the user completes authorization.

Common use cases:

  • Smart TV apps that display a code on screen for the user to approve on their phone
  • CLI tools that open a browser for the user to authenticate
  • IoT devices with no keyboard or screen that print a code to serial output
  • Kiosk and point-of-sale terminals

How It Works

The device flow is a two-channel protocol. The device communicates with the token endpoint, while the user interacts with Auris in a browser on a separate device:

  1. The device sends a token request to /api/oauth/device/code with its client_id and requested scope
  2. Auris returns a device_code (opaque, long), a user_code (short, human-readable, 8 characters), a verification_uri, and a polling interval
  3. The device displays the user_code and verification_uri to the user
  4. The user visits the verification URL in a browser, enters the code, and authenticates with Auris
  5. Meanwhile, the device polls POST /api/auth/token with grant_type=urn:ietf:params:oauth:grant-type:device_code at the specified interval
  6. Once the user approves, the next poll returns an access token and refresh token
  7. If the user denies or the code expires, the poll returns an error

Console Setup

Enable Device Flow

In the Auris Console, go to Applications and select the application that will use the device flow. Under the Settings tab, toggle Enable Device Flow to on.

Configure Settings

Set the device code lifetime and polling interval:

SettingDefaultNotes
Code Lifetime600 seconds (10 minutes)Maximum time the user has to enter the code and approve
Polling Interval5 secondsMinimum interval between token polling requests from the device
User Code Length8 charactersAlphanumeric, uppercase, easy to read and type

Note the Client ID

Device flow uses a public client (no client secret). Copy the Client ID from the Credentials tab.


Implementation

import { AurisClient } from '@auris/js' const auris = new AurisClient({ domain: 'auth.yourdomain.com', clientId: 'your-device-app-client-id', }) // Step 1: Request a device code const deviceAuth = await fetch('https://auth.yourdomain.com/api/oauth/device/code', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ client_id: 'your-device-app-client-id', scope: 'openid profile email', }), }).then(r => r.json()) // Step 2: Display to the user console.log(`Go to: ${deviceAuth.verification_uri}`) console.log(`Enter code: ${deviceAuth.user_code}`) // Step 3: Poll for the token const token = await pollForToken(deviceAuth) async function pollForToken(deviceAuth) { const interval = deviceAuth.interval * 1000 // convert to ms const expiresAt = Date.now() + deviceAuth.expires_in * 1000 while (Date.now() < expiresAt) { await new Promise(resolve => setTimeout(resolve, interval)) const response = await fetch('https://auth.yourdomain.com/api/auth/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'urn:ietf:params:oauth:grant-type:device_code', device_code: deviceAuth.device_code, client_id: 'your-device-app-client-id', }), }) if (response.ok) { return await response.json() } const error = await response.json() if (error.error === 'authorization_pending') { continue // user hasn't approved yet } if (error.error === 'slow_down') { await new Promise(resolve => setTimeout(resolve, 5000)) // back off continue } if (error.error === 'expired_token') { throw new Error('Device code expired. Please restart the flow.') } if (error.error === 'access_denied') { throw new Error('User denied the authorization request.') } throw new Error(`Unexpected error: ${error.error}`) } throw new Error('Device code expired.') }

Device Code Response

When you request a device code, Auris returns the following fields:

FieldTypeDescription
device_codestringOpaque code used by the device to poll for the token. Keep secret.
user_codestringShort alphanumeric code (8 characters) displayed to the user.
verification_uristringURL the user visits to enter the code.
verification_uri_completestringURL with the code pre-filled as a query parameter.
expires_innumberSeconds until the device code expires (default: 600).
intervalnumberMinimum polling interval in seconds (default: 5).

Error Handling

During the polling phase, the token endpoint returns specific error codes to indicate the current state:

Error CodeHTTP StatusMeaningClient Action
authorization_pending400User has not yet approved the requestContinue polling at the specified interval
slow_down400Polling too frequentlyIncrease polling interval by 5 seconds
expired_token400Device code has expiredRestart the flow from step 1
access_denied400User explicitly denied the requestShow error message, do not retry

User Verification Page

Auris provides a hosted verification page at /hosted/device where users enter their device code. The page:

  1. Prompts the user to enter the 8-character code
  2. Authenticates the user (login required if no active session)
  3. Shows the requesting application name and requested scopes
  4. Asks the user to approve or deny the request
  5. Displays a confirmation message on success

If the verification_uri_complete URL is used, the code field is pre-filled, saving the user a step.


Security Considerations

  • Short code lifetime: Device codes expire after 600 seconds by default. This limits the window for code interception.
  • Human-readable codes: The 8-character user codes use an unambiguous character set (no 0/O, 1/I/l confusion).
  • Rate-limited polling: The token endpoint enforces the polling interval. Clients that poll too fast receive slow_down errors.
  • One-time use: Each device code can only be approved once. After successful token issuance, the code is invalidated.

API Endpoints

POST/api/oauth/device/code

Request a new device code. Requires client_id and optional scope in the request body. Returns device_code, user_code, verification_uri, expires_in, and interval.

POST/api/auth/token

Token endpoint. For device flow, set grant_type=urn:ietf:params:oauth:grant-type:device_code, device_code, and client_id. Returns access token on success, or an error code during polling.

GET/api/oauth/device/verify

Hosted verification page. Accepts optional user_code query parameter for pre-filling.

GET/api/oauth/device/codesRequires: manage:device_codes

List active device codes for the tenant. Admin endpoint for monitoring and debugging.


Required Permissions

OperationPermission
Enable Device Flow on an applicationmanage:applications
List active device codesmanage:device_codes
Revoke a device codemanage:device_codes
Request/poll for tokenNo permission required (public endpoint)