Beta

Create a tenant

A new tenant starts with its own users, OAuth settings, audit history and logs. You are its first Tenant Admin.

BTL Admin

OAUTH 2.0 · LAB

Approve a photo frame on another screen with device authorization

Planned: start a device authorization as a photo frame, approve it on your phone, and poll for the result. Today, confirm what the tenant offers and use the loopback flow a browser-capable tool should use.

PlannedUses your lab tenant

The lesson

Builds on: Public and confidential clients.

New to the labs? Start with the lab toolkit and the shared cast and names every lab uses.

Planned. The core of this lab waits on platform features that are not built yet. The planned walkthrough shows exactly how it will run; Do today is a real exercise you can do now.

Request console

Requests in this lab can be sent from this page to your tenant: open one and choose Send. Fill in the values below first. They stay in this page's memory and are gone when you leave; secrets are never stored or sent anywhere except the request you send.

Setup

  1. Set ISSUER and APP_ID (the lab-printer-app client ID) in your shell, and define enc as in the earlier labs.

Planned walkthrough

These steps need the device authorization grant (G5). They are written exactly as they will run.

  1. Allow the grant and register the frame. In OAuth > Flow policy, tick Device authorization. Create a temporary public client lab-tmp-frame from a Device preset, with the device authorization grant and no redirect URIs. Choose the tenant's user code format and length, code lifetime and minimum polling interval. Set FRAME_ID to its client ID.

  1. The frame asks. It is a public client, so it sends only its client ID.

curl -s -d "client_id=$FRAME_ID" -d scope=photos.read "$ISSUER/oauth/device_authorization" | jq

The answer has device_code, user_code (for example WDJB-MJHT), verification_uri ($ISSUER/oauth/device), verification_uri_complete, expires_in and interval. Keep DEVICE_CODE in the shell; show only the user code and the address, as the frame's screen would.

  1. The frame polls before anyone has approved.

curl -s -d grant_type=urn:ietf:params:oauth:grant-type:device_code -d "device_code=$DEVICE_CODE" -d "client_id=$FRAME_ID" "$ISSUER/oauth/token" | jq

The answer is 400 authorization_pending. Poll again sooner than interval: slow_down, and the frame adds five seconds to its interval for the rest of the attempt.

  1. Approve on another device. On your phone or in a second browser, open verification_uri, sign in as Ava and type the user code. The approval page says a device is asking, names lab-tmp-frame and lists photos.read. Approve.

  1. The next poll returns an ordinary token response with an access token for Ava.

  1. Arrive through verification_uri_complete on a fresh attempt. The page still shows the code and asks Ava to confirm that it matches the code on the frame's screen. With the frame's screen in front of you, compare them before approving.

  1. Planned failure cases: choose Deny (the next poll answers access_denied), let a code lapse (expired_token), and type a wrong user code several times (refused, then rate limited with 429 and a visible usage limit). Audit records each stage.

Do today

  1. Read what the tenant advertises.

curl -s "$ISSUER/.well-known/openid-configuration" | jq '{device_authorization_endpoint, grant_types_supported, btl_service_status}'

There is no device authorization endpoint, no device grant, and btl_service_status is "partial". Flow policy lists Device authorization under "Not yet available".

  1. Ask the catalogued endpoint anyway.

POST$ISSUER/oauth/device_authorization Open in console
POST $ISSUER/oauth/device_authorization HTTP/1.1
Content-Type: application/x-www-form-urlencoded

client_id=$APP_ID&scope=photos.read

The answer is 501 with {"error":"temporarily_unavailable","error_description":"This endpoint is not implemented yet."}.

  1. Poll the token endpoint with the device grant type, as a frame would.

curl -s -d grant_type=urn:ietf:params:oauth:grant-type:device_code -d device_code=none -d "client_id=$APP_ID" "$ISSUER/oauth/token" | jq

The answer is unsupported_grant_type. The full URN is how extension grants are named; this server does not implement this one.

  1. Use the flow the lesson recommends for a tool that can open a browser. Treat lab-printer-app as a command-line tool: run btl-lab callback --port 8765 in a second terminal, then open the authorization request in the system browser.

eval "$(btl-lab pkce)"; eval "$(btl-lab state)"
echo "$ISSUER/oauth/authorize?response_type=code&client_id=$APP_ID&redirect_uri=$(enc http://127.0.0.1:8765/callback)&scope=photos.read&state=$STATE&code_challenge=$CHALLENGE&code_challenge_method=S256"

Sign in as Ava and approve. The listener prints the code, and the tool exchanges it with its verifier as in the Public and confidential clients lab. Approval and result stay together on one device, which the device grant cannot offer.

Check your work

Today, in tenant Logs: oauth.device rejected not_implemented with status 501, and oauth.token rejected unsupported_grant_type with status 400. Audit has the loopback flow's oauth.authorize code_issued and oauth.token succeeded for lab-printer-app.

Once G5 exists, the lab will check device code issue, user code acceptance, approval or denial, and token issue in Audit.

Cleanup

None today. The planned walkthrough deletes lab-tmp-frame and unticks Device authorization in Flow policy when it finishes.

Missing infrastructure

  • G5, device authorization grant. The device authorization endpoint; a tenant-hosted verification page with user code entry and the match-the-screen confirmation for verification_uri_complete; polling answers authorization_pending, slow_down, access_denied and expired_token; a Flow policy option and a per-client grant; tenant settings for user code format and length, code lifetime and polling interval; attempt limits on code entry shown as a usage limit; and Audit events for each stage. With it, every step of the planned walkthrough runs as written.

Back to all labs

We value your privacy

We use cookies and similar technologies to enhance your browsing experience, and analytics to understand our traffic. By clicking "Allow All", you consent to optional analytics. Cookie Policy

The Lab