Device authorization flow
Device authorization is for clients that cannot safely hold an application client-auth private key: CLIs, launchers, terminal tools, shared devices, and other public clients. The client asks Sudomimus for a short-lived deviceCode / userCode pair, shows the user a code, sends them to the browser, and polls until approval turns into ordinary Sudomimus application tokens.
The flow follows the OAuth 2.0 Device Authorization Grant (RFC 8628) model: the initiating client receives a device code and a user code, the user approves in a browser-capable user agent, and the client polls until the authorization is complete. Sudomimus keeps the standard device-flow shape while returning Sudomimus application tokens.
This is a separate integration path from Connect and Native direct-issue:
| Path | What proves the request |
|---|---|
| Connect | A client-auth JWT signed by the application’s private key |
| Native direct-issue | A platform credential such as a Steam ticket or AccessKey secret |
| Device authorization | A public client starts a code session; the browser user approves it |
The public HTTP surface is device-api.sudomimus.com. The browser approval page is still hosted by via.sudomimus.com.
Protocol overview
Section titled “Protocol overview”| Step | Actor | Endpoint | Result |
|---|---|---|---|
| 1. Start | Client | device-api POST /device-authorize | { deviceCode, userCode, verificationUri, verificationUriComplete, expiresIn, interval } |
| 2. Approve | User in browser | via.sudomimus.com/device | The user signs in, confirms the displayed code, and approves or denies |
| 3. Poll | Client | device-api POST /device-token | Pending state, polling instruction, denial, expiry, or { accessToken, refreshToken } |
| 4. Continue | Client | connect-api POST /refresh | Later token rotation uses the normal Connect token operations |
Only the client sees deviceCode. Only the user sees and confirms userCode. A successful /device-token response consumes the device session, so the same deviceCode cannot mint another token pair.
1. Start device authorization
Section titled “1. Start device authorization”The client starts by posting its application anchor:
curl -X POST https://device-api.sudomimus.com/device-authorize \ -H "Content-Type: application/json" \ -d '{ "applicationAnchor": "your-application" }'Successful response:
{ "applicationAnchor": "your-application", "deviceCode": "dvc_...", "userCode": "WDJB-MJHT", "verificationUri": "https://via.sudomimus.com/device", "verificationUriComplete": "https://via.sudomimus.com/device?user_code=WDJB-MJHT", "expiresIn": 600, "interval": 5}/device-authorize does not accept a client-auth JWT. The application opts in through configuration instead: it must have an enabled Layer 3 DEVICE_CODE ReturnRule. If that rule is missing, the request is refused.
2. Send the user to the browser
Section titled “2. Send the user to the browser”Show the userCode clearly in the client UI and ask the user to open the browser approval page:
Visit https://via.sudomimus.com/deviceEnter code: WDJB-MJHTWhen possible, open verificationUriComplete instead. It pre-fills the code and is also the best target for QR-code or clickable terminal output:
https://via.sudomimus.com/device?user_code=WDJB-MJHTThe browser page displays the application and code again before approval. The user should compare the browser code with the code shown by the client. The browser never receives deviceCode and never displays access or refresh tokens; it only approves or denies the pending session.
3. Poll for tokens
Section titled “3. Poll for tokens”The client polls /device-token with the private deviceCode:
curl -X POST https://device-api.sudomimus.com/device-token \ -H "Content-Type: application/json" \ -d '{ "deviceCode": "dvc_..." }'Poll no faster than the returned interval. While the user is still working, /device-token returns an OAuth-style polling error:
{ "error": "authorization_pending"}After approval, the same endpoint returns ordinary Sudomimus application tokens:
{ "applicationAnchor": "your-application", "accessToken": "...", "refreshToken": "...", "claims": { "email": { "requirement": "OPTIONAL", "state": "GRANTED" }, "firstName": { "requirement": "OFF", "state": "UNKNOWN" }, "lastName": { "requirement": "OFF", "state": "UNKNOWN" } }}The claims block explains the application’s claim policy joined with the user’s standing sharing decision. The actual token payload follows the normal Sudomimus token rules.
4. Use Connect for later token operations
Section titled “4. Use Connect for later token operations”Device authorization only owns the initial public-client exchange. Once /device-token succeeds, the refresh token belongs to the normal Sudomimus application session model.
Use Connect API token operations afterward:
POST /refreshto rotate the refresh token and issue a new access token.POST /logoutto end the current refresh-token family.POST /introspectto inspect a token.POST /revoke-allfor application-level session revocation.
See Managing sessions for those operations and Device polling and errors for the polling state machine.
Application configuration
Section titled “Application configuration”An application must allow the browser-side authentication and realization checks it wants users to pass:
| Layer | Requirement |
|---|---|
| Layer 1 | Existing authentication methods such as email OTP or passkeys |
| Layer 2 | Existing identity rules that allow the realized account |
| Layer 3 | A DEVICE_CODE ReturnRule |
DEVICE_CODE is a Layer 3 return method, not a new authentication method. The user still signs in through the application’s ordinary Layer 1 methods and is still checked against Layer 2 before the device session can be approved.
When to choose this path
Section titled “When to choose this path”Use device authorization when your client is public and cannot keep a client-auth private key secret. That is the usual fit for a CLI distributed to users, a launcher installed on a desktop, a terminal-only environment, or a shared-screen device that needs the user to finish sign-in on another browser-capable device.
Use Connect browser polling instead when you have a confidential application backend that can sign /establish. Use Native direct-issue when the client has a platform credential such as a Steam ticket or a pre-issued AccessKey.
The raw endpoint contract is published in the Device API reference.