โ All flows
Device Authorization Flow
For TVs, consoles and other devices without a keyboard
The Device Authorization flow (also called the device code flow) lets a device with no browser or easy typing ask for access. It works in three moves:
- The device shows a short
user_codeand a web address. - The user opens that address on their phone or computer and approves the request.
- Meanwhile the device polls (checks in repeatedly) until approval arrives.
See it step by step
๐ง
YouThe person using the app๐บ
DeviceA TV or other gadget without a keyboard๐
Login serverChecks who you are and hands out tokens๐ฆ
APIHolds the data the app wantsRequest codes
Step 1 of 6
The device asks for a code
The device tells the login server it wants to sign someone in. It gets back a long secret device_code for itself and a short user_code for you.
When to use this flow
- Smart TVs and streaming boxes โ Typing passwords with a remote is painful
- Games consoles and IoT devices โ No browser, or a very limited one
- Command-line tools โ Sign in without a redirect URL
- Web and mobile apps โ Use Authorization Code with PKCE instead
Good practices
- Poll at the given
intervalโ Wait at leastintervalseconds, and slow down if told to - Show the code and address clearly โ Make it easy to type and to recognise
- Stop when the code expires โ Start over with a new
device_code - Handle denial โ If the user says no, the server returns
access_denied
Common mistakes
- Polling too fast โ You will be told to
slow_downor be blocked - Showing the
device_codeto the user โ Only theuser_codeis meant to be seen - Using it when a browser is available โ Authorization Code with PKCE is simpler there
- Skipping expiry handling โ Codes usually expire after about 15 minutes
Code example
Device Authorization example
javascript
// Device Authorization flow, device side
const start = await fetch('https://auth.provider.com/oauth/device/code', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({ client_id: CLIENT_ID, scope: 'profile' }),
}).then((r) => r.json());
console.log(`Go to ${start.verification_uri} and enter ${start.user_code}`);
let interval = start.interval ?? 5;
while (true) {
await new Promise((r) => setTimeout(r, interval * 1000));
const res = await fetch('https://auth.provider.com/oauth/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: start.device_code,
client_id: CLIENT_ID,
}),
});
const body = await res.json();
if (body.error === 'authorization_pending') continue;
if (body.error === 'slow_down') { interval += 5; continue; }
if (body.error) throw new Error(body.error); // access_denied or expired_token
return body; // { access_token, ... }
}