Skip to content

Device authorization flow

View as Markdown

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:

PathWhat proves the request
ConnectA client-auth JWT signed by the application’s private key
Native direct-issueA platform credential such as a Steam ticket or AccessKey secret
Device authorizationA 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.

StepActorEndpointResult
1. StartClientdevice-api POST /device-authorize{ deviceCode, userCode, verificationUri, verificationUriComplete, expiresIn, interval }
2. ApproveUser in browservia.sudomimus.com/deviceThe user signs in, confirms the displayed code, and approves or denies
3. PollClientdevice-api POST /device-tokenPending state, polling instruction, denial, expiry, or { accessToken, refreshToken }
4. ContinueClientconnect-api POST /refreshLater 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.

The client starts by posting its application anchor:

Terminal window
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.

Show the userCode clearly in the client UI and ask the user to open the browser approval page:

Visit https://via.sudomimus.com/device
Enter code: WDJB-MJHT

When 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-MJHT

The 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.

The client polls /device-token with the private deviceCode:

Terminal window
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.

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 /refresh to rotate the refresh token and issue a new access token.
  • POST /logout to end the current refresh-token family.
  • POST /introspect to inspect a token.
  • POST /revoke-all for application-level session revocation.

See Managing sessions for those operations and Device polling and errors for the polling state machine.

An application must allow the browser-side authentication and realization checks it wants users to pass:

LayerRequirement
Layer 1Existing authentication methods such as email OTP or passkeys
Layer 2Existing identity rules that allow the realized account
Layer 3A 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.

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.