skip to content

Device Authorization

How a TV or a terminal with no browser gets a token: it shows a short user code you approve elsewhere, then polls the token endpoint until you do. The polling rules are what interviewers probe.

part ofOAuth 2.0overview, primer and where to startread it →
on this pageshow

questions

4

What must a device-grant client do when the token endpoint answers slow_down, and what interval applies if none was sent?

level: middleimportance: must knowfreq 50%

answer

  1. two numbers, both are five
  2. the default when interval is absent
  3. slow_down is still a pending answer
  4. the increase is not a one-off
  5. add five, keep it for every later poll

basics

~20 s

A slow_down answer means the client must add 5 seconds to its polling interval for this and every later request — a permanent increase, not a one-off pause. Where the response supplied no interval, the client must use 5 seconds.

solid answer

~30 s

Two numbers carry this whole contract. If the device authorization response omitted `interval`, the client must use **5 seconds** as its default wait between polls. When the token endpoint answers `slow_down`, the client must **increase its interval by 5 seconds** — and the increase applies to this request and all subsequent ones, so it is a lasting change rather than a single skipped beat. `slow_down` is otherwise a variant of `authorization_pending`: the authorization request is still outstanding and polling continues. The loop ends on a token response, on `access_denied`, on `expired_token`, or when the client's own deadline derived from `expires_in` passes.

code

pseudocode · 21 lines
pseudocode
interval = response.interval if present else 5      // seconds
deadline = now + response.expires_in

loop:
    if now >= deadline:
        stop "device code expired"
    wait interval seconds
    result = post token request with device_code

    if result is token response:
        stop "authorized"
    if result.error is "authorization_pending":
        continue
    if result.error is "slow_down":
        interval = interval + 5        // stays raised
        continue
    if result.error is "access_denied":
        stop "user refused"
    if result.error is "expired_token":
        stop "device code expired"
    stop "protocol error"

go deeper

for a junior

Remember the default: with no interval supplied, wait 5 seconds between polls, and keep polling while the answer says the request is still pending.

for a middle

State both numbers precisely and make clear that a slow_down raise is permanent for the rest of the flow, not a single skipped poll.

for a senior

Bring the operational half: your own deadline from expires_in, jitter so a fleet does not poll in lockstep, and branching on the error member rather than the status code.

for a principal

Weigh the aggregate cost across a device estate — poll volume against how quickly a user expects the screen to change — and decide what your token endpoint must be sized for.

## The two numbers an interviewer is fishing for This is the sharpest factual question on the device authorization grant, and it is small enough to state in two lines: 1. **No `interval` in the device authorization response means 5 seconds.** The client must use 5 as its default minimum wait between polls of the token endpoint. 2. **`slow_down` means add 5 seconds, permanently.** The interval must be increased by 5 seconds for this request and all subsequent requests. Most candidates get the first and fumble the second, because "slow down" sounds like a one-off instruction to pause. It is not. A client polling at 5 seconds that receives one `slow_down` polls at 10 seconds from then on; a second `slow_down` takes it to 15, and it never drifts back down within that flow. ## Why the increase is permanent The authorization server has no way to reach the device and say "you may speed up again". There is no channel in that direction — that absence is the founding assumption of the whole grant. A back-off that expired on its own would let a misbehaving client return to hammering the token endpoint every few seconds, and the server would have to send `slow_down` again to stop it, which costs exactly the round trip it was trying to prevent. Making the raise stick means one message is enough. ## `slow_down` is still a pending answer It is easy to read `slow_down` as a rejection. It is not: the specification defines it as a variant of `authorization_pending`. The authorization request is alive, the user may still be typing the `user_code` on their phone, and the client keeps polling — just further apart. Treating it as terminal abandons a flow the user is about to complete. ## What actually ends the loop | Outcome | Terminal? | What it means | |---|---|---| | token response | yes | the user approved; use the access token | | `authorization_pending` | no | still waiting; poll again after the interval | | `slow_down` | no | still waiting; raise the interval by 5 seconds first | | `access_denied` | yes | the user refused the request | | `expired_token` | yes | the `device_code` outlived its `expires_in` | A well-built client also keeps its own deadline. `expires_in` from the device authorization response says how many seconds the `device_code` is good for, so the client can compute the moment the flow dies and stop cleanly — showing the user a fresh code rather than waiting for the server to say `expired_token`. ## The interval is a floor, not a schedule `interval` is the **minimum** time between polls. Nothing stops a client waiting longer, and there are good reasons to. The classic production failure with this grant is a fleet of identical devices that all restart together — after a power cut on site, or a coordinated firmware rollout — and then poll the token endpoint in lockstep, at the same second, forever. Adding a small random offset to each device's wait costs nothing and turns a synchronised spike into a flat line. Respecting the floor is required; treating it as an exact metronome is a choice, and usually the wrong one at scale. ## What ignoring the interval buys you Nothing good. A client that polls every second does not learn of the approval meaningfully sooner — the user is on their phone, operating at human speed — and each `slow_down` it provokes pushes its own interval further up. The end state of ignoring the contract is a client that polls *less* often than one that respected it from the start. ## Version note These rules come from RFC 8628 and are unchanged by OAuth 2.1, which leaves the device authorization grant in place as an extension.

  • What ends the polling loop besides a successful token response?
    Three things. `access_denied` means the user refused, and `expired_token` means the `device_code` has outlived its `expires_in` — both are terminal and the device must start a fresh device authorization request to try again. The third is the client's own deadline, computed from `expires_in` when the codes were issued, which lets it stop and display a new code without waiting for the server to tell it the old one is dead.
  • Why should identical devices not all poll exactly on the interval?
    Because `interval` is a minimum, not a schedule, and a fleet that restarts together will poll in lockstep on the same second indefinitely. That converts an evenly spread load into a periodic spike at the token endpoint. Adding a small random offset per device keeps every client inside the contract while flattening the aggregate, and costs the user nothing they can perceive.

It is a service counter with no way to call you back: the only feedback you get for asking too often is being told to ask less often, and that instruction stays in force for the rest of the wait.

saying these in an interview costs you the question

  • Says slow_down pauses one poll then restores the old interval
  • Treats slow_down as a refusal and stops polling
  • Guesses the default interval instead of 5 seconds
  • Thinks the server can later tell the client to speed up
  • Polls as fast as possible to get the token sooner
open as a page

How does a device with no browser redeem its device_code at the token endpoint, and with which grant_type?

level: middleimportance: must knowfreq 56%

basics

~10 s

The device POSTs to the token endpoint with grant_type set to urn:ietf:params:oauth:grant-type:device_code, plus its device_code and client_id. Until the user approves it gets an error response carrying authorization_pending, then a normal token response.

open as a page

In the OAuth 2.0 device authorization grant, what does a browserless device display, and where does the user approve it?

level: juniorimportance: should knowfreq 44%

basics

~20 s

The device displays a short user_code and a verification_uri. The user opens that URI on a separate phone or laptop, signs in there and enters the code. The device keeps a long device_code the user never sees.

open as a page

Why is a device-grant user_code kept short, and what must the authorization server do about the guessing risk?

level: seniorimportance: should knowfreq 38%

basics

~20 s

The user_code is retyped by a human on a second device, so it is short, case-insensitive and drawn from a reduced character set. That costs entropy, and the compensation sits with the authorization server: rate-limit attempts at the verification page and keep the code short-lived and one-time.

open as a page