Imagine signing in on a smart TV with the on-screen keyboard. Or on a CLI tool with no browser. RFC 8628 (the device authorization grant) solves these cases by splitting the sign-in across two devices: the input-poor device shows a short code, and the user types it into a browser on their phone or laptop.
This is the right flow whenever the user-facing device cannot host a usable browser.
The flow at a glance
Section titled “The flow at a glance”The poll is the unusual part. The device repeatedly asks "is the user done yet?" until the platform answers yes (with a token) or no (with an error).
The wire format
Section titled “The wire format”Step 1 — the device requests a code:
POST https://<your-tenant-url>/oauth2/device_authorizationContent-Type: application/x-www-form-urlencoded
client_id=<your-client-id>&scope=openid+profile+email+offline_accessResponse:
{ "device_code": "abc123long-opaque-string", "user_code": "WDJB-MJHT", "verification_uri": "https://banking-cymmetri.intelliauth.local/activate", "verification_uri_complete": "https://banking-cymmetri.intelliauth.local/activate?user_code=WDJB-MJHT", "expires_in": 1800, "interval": 5}Show the user user_code and verification_uri. If the device can show a QR code, encode verification_uri_complete — the user scans the QR and lands on the activation page with the code pre-filled.
Step 2 — the device polls:
POST https://<your-tenant-url>/oauth2/tokenContent-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=abc123long-opaque-string&client_id=<your-client-id>Possible responses:
authorization_pending— keep polling.slow_down— you polled too fast; increase the interval by 5 seconds before next poll.expired_token— the device_code expired; restart from step 1.access_denied— the user denied the request.- A normal token response — the user signed in; you're done.
Respect the interval field. Polling faster than that gets you throttled.
When to use this flow
Section titled “When to use this flow”- Smart TVs and streaming devices — the canonical case.
- CLIs —
gh auth login,aws sso login, and similar tools use device code. The CLI prints the URL + code; the user finishes sign-in in a browser; the CLI receives the token. - IoT devices with a screen but no keyboard — same shape.
- Devices in shared environments — kiosks, gym treadmills, anything where typing a password on the public device feels wrong.
If the device can host a browser (a phone, a tablet, a desktop), prefer authorization code with PKCE instead — fewer round trips, no polling overhead.
The user experience knob
Section titled “The user experience knob”The user_code is intentionally short and humans-friendly. The format is "two alphabetic groups separated by a dash" — short enough to type quickly, distinct enough to be unambiguous when read aloud. Show it in a large font, in mixed case. Show the URL too, for users whose phones cannot scan QR codes.
The activation page on the IntelliAuth side accepts the code, asks the user to sign in (if not already), then shows a consent screen describing which device is requesting access. This is the user's chance to back out — important for shared TVs.
Storing tokens on the device
Section titled “Storing tokens on the device”Same rules as native apps: use the platform's secure storage if it has one. If the device has no secure storage (a raw embedded system), assume the token can be extracted and design accordingly — keep scopes narrow, rotate refresh tokens aggressively, support revocation.