The device authorization grant (RFC 8628) lets a CLI, SDK, or any input-constrained device authenticate a user without requiring a browser on the same machine. The device displays a short code or URL; the user completes login on any browser they have available.
PymtHouse extends the standard RFC 8628 flow with optional third-party initiate login (OIDC Core §4): unauthenticated users can be redirected to your own login UI instead of PymtHouse’s default login page.
When to use device flow
Use this pattern when:
- Your integration runs as a CLI tool, background daemon, or terminal app.
- The user’s device has limited or no browser access at the point of authentication.
- You want to bridge an existing IdP session (NaaP / Option B) into PymtHouse without requiring a second login.
For browser-based authentication, use Interactive login instead.
Prerequisites
- A public OIDC client (
app_…) with the device_code grant enabled.
- If using third-party initiate:
device_third_party_initiate_login must be enabled on the public client, and an initiate_login_uri must be registered.
- If completing the device grant from your backend (Option B): a confidential M2M client (
m2m_…) with users:token or device:approve scope.
The full flow
Step 1 — Request a device code
Response:
verification_uri vs verification_uri_complete:
Step 2 — Display the code to the user
Show either the short URL with the user_code to type in, or present the verification_uri_complete as a clickable link or QR code.
Step 3 — Poll for the token
Begin polling the token endpoint at the interval specified in the response. Do not poll faster than the interval — the server will respond with slow_down and increase the interval.
Poll response codes:
Third-party initiate login (Option B / NaaP)
When device_third_party_initiate_login is enabled on the public client, unauthenticated users who open verification_uri_complete are redirected to your registered initiate_login_uri with:
Your initiate_login_uri endpoint must:
- Validate
iss against your discovery document. Reject if it does not equal the expected issuer.
- Validate
target_link_uri — ensure it points to your PymtHouse origin and the /oidc/device path. Reject open redirects.
- Complete the user’s login at your own IdP.
- Call
POST {issuer}/token with an RFC 8693 token exchange to bind the device grant (see Token exchange — device completion).
- Show an approval confirmation page or redirect to
target_link_uri.
The initiate_login_uri is loaded from the database for the client_id. The endpoint does not accept an arbitrary initiate_login_uri query parameter. This is intentional to prevent open-redirect attacks.
Security requirements for your initiate login endpoint
- Use HTTPS in production. HTTP on
localhost is permitted for local development only.
- Apply CSRF protection on any form that triggers your IdP login.
- The OP sets a short-lived per-client cookie so that a failed relying-party round-trip does not loop redirects indefinitely.
Implied consent
When the user opens verification_uri_complete with a pre-filled user_code, PymtHouse skips the secondary authorization confirmation step after a successful lookup — the user already authenticated at your site. This improves UX by avoiding double-confirmation for users who completed login through the third-party initiate flow.
Key design decisions
verification_uri_complete carries iss alongside user_code. Including the issuer in the URL allows the device verification page to validate that the user_code was issued by this deployment and not by a phishing URL. It also enables the third-party initiate redirect to carry context without requiring a server-side lookup.
- Redirect target is database-loaded, not URL-provided. Accepting an arbitrary
initiate_login_uri query parameter would allow a crafted device-auth link to redirect any user to an attacker-controlled URL. Loading the URI from the client registration prevents this class of open-redirect vulnerability.
- Third-party device login must be explicitly opt-in. Defaulting to a redirect to the relying party would silently change the user experience for every device session. Requiring explicit opt-in means the impact of enabling the feature is deliberate and visible.
- RFC 8628 polling semantics are enforced server-side.
slow_down responses enforce back-off at the server rather than trusting clients to self-regulate. This protects the token endpoint under high load or misbehaving clients.
Implementation tasks
- Validate that your device code flow handler parses and acts on every polling error code — particularly
slow_down and expired_token.
- If using third-party initiate, register
initiate_login_uri as an HTTPS URL; verify it strictly matches iss from discovery before trusting any payload.
- Enable CSRF protection on your
initiate_login_uri handler.
- Do not display
device_code to the user — it is a server-side opaque token. Display only user_code and the verification URLs.
- After binding the device grant with RFC 8693 (Option B), verify the CLI poll returns a successful token before showing the “device approved” page to the browser.