Device Authorization Flow Low-Level Design: Device Code, Polling, and Token Binding

What Is the Device Authorization Flow?

The OAuth 2.0 Device Authorization Grant (RFC 8628) enables input-constrained devices — smart TVs, game consoles, CLI tools, IoT devices — to obtain tokens without requiring the user to type credentials on the device itself. The device displays a short human-readable code and a URL; the user navigates to that URL on a secondary device (phone or browser), authenticates, and enters the code. The device polls the authorization server until the user approves or the code expires.

Requirements

Functional Requirements

  • Issue a device_code (opaque, machine-facing) and a user_code (short, human-typable) on flow initiation.
  • Present the user with a verification URL and user_code on the constrained device.
  • Allow the user to authorize on a secondary device by visiting the URL and authenticating.
  • The device polls the token endpoint; receive a token when approved, appropriate error codes when pending or expired.
  • Bind the issued tokens to the device_code to prevent token use on a different device.
  • Expire device codes after a configurable TTL (default 15 minutes) and enforce polling interval backoff.

Non-Functional Requirements

  • User code must be collision-resistant within the TTL window and easy to type (uppercase alpha, no ambiguous characters).
  • Polling must not create undue load; enforce minimum interval and exponential backoff on violations.
  • The authorization state must be durable across restarts during the polling window.

Data Model

Device Authorization Record

  • device_code — cryptographically random 32-byte value, hex-encoded; never shown to the user.
  • user_code — 8 uppercase characters (BCDFGHJKLMNPQRSTVWXZ, excluding vowels and visually ambiguous chars); mapped to device_code.
  • client_id, scope, audience.
  • status — ENUM: PENDING, APPROVED, DENIED, EXPIRED.
  • user_id — populated when a user approves; null until then.
  • device_binding_hash — hash of device fingerprint (user agent, IP, client_id); used at token pickup to verify same device is polling.
  • issued_at, expires_at, last_polled_at, interval_seconds.

Core Algorithm

Step 1 — Flow Initiation (Device Request)

The device sends a POST to /device/code with client_id and scope. The server generates a cryptographically random device_code and a user_code. The user_code is generated by selecting 8 characters from the allowed set using a CSPRNG, then checking for collisions against PENDING codes in the store (retry on collision, expected to be rare). Store the authorization record with status PENDING and a TTL. Return device_code, user_code, verification_uri, verification_uri_complete (URI with user_code pre-filled), expires_in, and interval to the device.

Step 2 — User Authorization (Secondary Device)

The user navigates to the verification URL, authenticates, and enters the user_code. The server looks up the record by user_code, verifies it is PENDING and not expired, displays the requested scope, and prompts the user to approve or deny. On approval: atomically set status to APPROVED and populate user_id. On denial: set status to DENIED.

Step 3 — Device Polling

The device polls POST /token with grant_type=urn:ietf:params:oauth:grant-type:device_code and device_code. The server checks:

  • Status PENDING: return error authorization_pending; update last_polled_at.
  • Status APPROVED: issue access token and refresh token (bound to device_binding_hash); mark record consumed.
  • Status DENIED: return error access_denied.
  • Status EXPIRED or not found: return error expired_token.
  • Polling faster than interval: return error slow_down and increment interval by 5 seconds.

Step 4 — Device-Bound Token Issuance

At token issuance, include the device_binding_hash as a private claim in the access token and as a field in the refresh token record. Resource servers that require device binding verify this claim against the current request fingerprint. For less sensitive resources, the binding hash is informational only.

API Design

  • POST /device/code — initiate flow; returns device_code, user_code, verification_uri, expires_in, interval.
  • GET /device — renders the user-facing authorization page (enter user_code + authenticate).
  • POST /device/authorize — submit user approval or denial for a user_code.
  • POST /token with grant_type=urn:ietf:params:oauth:grant-type:device_code — device polling endpoint.

Scalability Considerations

Store authorization records in Redis with native TTL; the polling pattern (many reads per record) benefits from Redis throughput. Use a secondary index (sorted set) on user_code to support O(1) lookup during user authorization without scanning. Rate-limit polling per device_code using a token bucket in Redis. For high-volume IoT deployments, shard the device authorization store by a hash of client_id. Long-poll variants reduce polling frequency: the device holds a connection open for up to the interval duration; the server responds immediately when status changes. This trades connection overhead for reduced polling load.

Summary

The device authorization flow solves the input-constrained device problem through short human-typable codes, secondary-device authentication, and polling-based token pickup. Collision-resistant user code generation, strict polling interval enforcement, and device binding at token issuance make the flow both usable and secure at scale.

{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “How should the user code alphabet be designed in device authorization flow?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Use a restricted alphabet excluding visually ambiguous characters: remove 0/O, 1/I/l, 8/B, 5/S, 2/Z. A safe alphabet is ACDEFGHJKLMNPQRTUVWXY34679 (24 characters). An 8-character code from this set gives 24^8 ≈ 110 billion combinations — sufficient to prevent brute force within the short code lifetime (5-15 minutes). Format as two 4-character groups (e.g., ACDF-GHJK) for readability. Use a CSPRNG for generation.”
}
},
{
“@type”: “Question”,
“name”: “How does the polling state machine with slow_down work in device authorization?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “The device polls the token endpoint at the interval specified in the device authorization response (minimum 5 seconds per RFC 8628). The server responds with authorization_pending while the user has not yet acted. If the device polls faster than the interval, the server returns slow_down, and the device must increase its polling interval by 5 seconds for all subsequent polls. After the code expires, the server returns expired_token and the device must restart the flow.”
}
},
{
“@type”: “Question”,
“name”: “How is a device binding hash claim added to tokens in device authorization flow?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “When the device initiates the flow, it submits a device_identifier (hardware ID, installation ID, or a generated stable token). The server stores this alongside the device_code. On successful authorization, the issued access and refresh tokens include a device_hash claim: SHA-256(device_identifier) truncated to 128 bits. Resource servers can optionally verify the device_hash matches the requesting device, enabling device-bound token policies without storing raw device identifiers in tokens.”
}
},
{
“@type”: “Question”,
“name”: “How does a long-poll variant improve the device authorization flow?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Instead of repeated short polls, the device issues a single HTTP request to a long-poll endpoint that holds the connection open until the user approves, denies, or the code expires. The server uses an internal pub/sub mechanism (e.g., Redis Pub/Sub or SSE) to push the authorization event to the waiting connection immediately upon user action. This eliminates polling latency and reduces server load from repeated requests. Implement a server-side timeout equal to the code lifetime and return authorization_pending on timeout so the device can re-poll.”
}
}
]
}

See also: Netflix Interview Guide 2026: Streaming Architecture, Recommendation Systems, and Engineering Excellence

See also: Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering

See also: Atlassian Interview Guide

Scroll to Top