Device Authorization Grant
RFC 8628Client type: Input-constrained devices: Smart TVs, game consoles, CLI tools, IoT devices that cannot open a browser
The Device Authorization Grant (RFC 8628) lets devices with no browser or limited input (TV, CLI, IoT sensor) authorize by displaying a short code and URL. The user enters the code on another device (phone/computer). The device polls the authorization server until the user completes authorization. Used by YouTube on TV, Spotify on TV, GitHub CLI, AWS CLI.
How it works
The Device Flow solves the problem of authorizing a device that cannot open a browser or accept text input conveniently.
Flow: 1. Device POSTs client_id to /device_authorization 2. Server returns device_code, user_code, verification_uri, expires_in, interval 3. Device displays: 'Visit example.com/activate and enter code: ABCD-1234' 4. User visits the URL on their phone/computer and enters the code 5. Meanwhile, device polls /token every {interval} seconds with device_code 6. Authorization server returns 'authorization_pending' until user completes 7. Once user authorizes, next poll returns access_token and refresh_token
Polling: device must respect the interval (typically 5 seconds). Polling faster results in 'slow_down' error; device must then increase interval by 5 seconds.
User code format: short, human-typable, case-insensitive. Typically 8 characters in format XXXX-XXXX. Designed to be read from a TV screen at distance and typed on a phone.
Expiry: device_code and user_code expire after expires_in seconds (typically 1800 seconds / 30 minutes). If expired, device must restart the flow.
Error codes during polling: authorization_pending – user hasn't authorized yet, keep polling slow_down – polling too fast, increase interval by 5s access_denied – user denied, stop polling expired_token – device_code expired, restart flow
Flow Steps
- 1
Device POSTs client_id to /device_authorization endpoint
- 2
Server returns device_code, user_code (e.g., ABCD-1234), verification_uri, expires_in, interval
- 3
Device displays: 'Go to example.com/activate and enter: ABCD-1234'
- 4
User visits URL on phone/computer, enters code, authenticates and grants permission
- 5
Device polls /token every {interval} seconds with grant_type=urn:ietf:params:oauth:grant-type:device_code
- 6
On success, server returns access_token and refresh_token
Parameters
| Parameter | Required | Description |
|---|---|---|
| grant_type | Yes | urn:ietf:params:oauth:grant-type:device_code |
| client_id | Yes | Device application identifier |
| device_code | Yes | device_code returned from /device_authorization request |
Examples
# Step 1: Request device code
POST https://auth.example.com/device_authorization
Content-Type: application/x-www-form-urlencoded
client_id=tv_app&scope=read:library
# Response:
{
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
"user_code": "WDJB-MJHT",
"verification_uri": "https://example.com/device",
"verification_uri_complete": "https://example.com/device?user_code=WDJB-MJHT",
"expires_in": 1800,
"interval": 5
}
# Step 2: Display to user – poll every 5s
while (true) {
const res = await fetch('/oauth/token', {
method: 'POST',
body: 'grant_type=urn:ietf:params:oauth:grant-type:device_code' +
'&client_id=tv_app&device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS'
});
const data = await res.json();
if (data.access_token) break; // done
if (data.error === 'slow_down') interval += 5;
if (data.error === 'access_denied') throw new Error('User denied');
await sleep(interval * 1000);
}When to use
Smart TVs, game consoles, CLI tools (GitHub CLI, AWS CLI, gcloud), Raspberry Pi/IoT devices, any device where opening a browser is impractical.