Skip to content
Docs · TVs and command-line tools

TVs, consoles and command-line tools

A TV can’t easily show a sign-in page, and a command-line tool shouldn’t ask for a password. With the device flow, the device shows a short code, and the person types it into their environment’s Lobby on their phone or computer, where they are already signed in.

Register the app

In Usher Console, open the environment, then Applications → New application → TV or command line. It gets a client ID and no secret: a device can’t keep one.

The flow

Terminal
# 1. the device asks for a code
curl -s -X POST https://acme.id.hallelo.net/api/auth/device/code \
  -d client_id=YOUR_CLIENT_ID -d scope='openid email offline_access'
# → { "device_code": "…", "user_code": "6L95PBQQ",
#     "verification_uri": "https://acme.id.hallelo.net/device",
#     "verification_uri_complete": "https://acme.id.hallelo.net/device?user_code=6L95PBQQ",
#     "expires_in": 600, "interval": 5 }

# 2. it shows the code (and a QR code of verification_uri_complete), then polls
curl -s -X POST https://acme.id.hallelo.net/api/auth/oauth2/token \
  -d grant_type=urn:ietf:params:oauth:grant-type:device_code \
  -d device_code=… -d client_id=YOUR_CLIENT_ID
# → { "error": "authorization_pending" } until the person allows it,
#   then { "access_token": "…", "id_token": "…", "refresh_token": "…" }
  • Poll politely. Wait interval seconds between polls. Polling faster is answered slow_down.
  • Stop when told. access_denied means the person refused; expired_token means ten minutes passed. Ask for a new code.
  • Show the address too. Not everyone can scan a QR code: show verification_uri and the code, spaced like 6L95-PBQQ.

At /device, the Lobby shows the person which app is asking and for what. It tells them to go on only if they started it themselves and their device shows the same code.

Bind tokens to the device (DPoP)

A token copied off a device is still a token. With DPoP (RFC 9449), the device keeps a private key and sends a fresh signed proof with every request. A token bound to that key is useless without it.

  • Ask for bound tokens: send a DPoP header with your token requests, and Usher binds what it issues to your key (token_type is DPoP).
  • Require them: turn on Require DPoP when you create the app. Usher then issues it no token without a proof.
  • Use them with Authorization: DPoP <token>, plus a proof for that request.
  • Libraries: most OAuth libraries with DPoP support do all of this for you (openid-client’s DPoP option, for example).