Device polling and errors
Device authorization clients spend most of their time waiting. A good implementation treats /device-token as a state machine: pending means keep polling, slow_down means back off, terminal errors stop the flow, and success consumes the session.
Polling loop
Section titled “Polling loop”After POST /device-authorize, store deviceCode, show userCode, and start polling no faster than the returned interval.
let intervalSeconds = authorize.interval;
while (true) { await sleep(intervalSeconds * 1000);
const res = await fetch("https://device-api.sudomimus.com/device-token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ deviceCode: authorize.deviceCode }), });
const body = await res.json();
if (res.ok) { return body; // { accessToken, refreshToken, claims, ... } }
if (body.error === "authorization_pending") continue; if (body.error === "slow_down") { intervalSeconds = body.interval ?? intervalSeconds + 5; continue; }
throw new Error(body.error);}The server may return slow_down if the client polls too quickly. When that happens, use the returned interval for subsequent polls.
Polling errors
Section titled “Polling errors”POST /device-token uses the RFC 8628 device-flow error vocabulary for polling states. Branch on error; do not expect Sudomimus { "reason": "..." } wire reasons from this endpoint’s polling outcomes.
| Error | Meaning | Client behavior |
|---|---|---|
authorization_pending | The user has not approved or denied yet. | Keep polling after the current interval. |
slow_down | The client is polling too quickly. | Increase the interval; use interval if present. |
access_denied | The user denied the request, approval failed, or policy no longer allows issuance. | Stop polling and show a denied/failed state. |
expired_token | The device authorization session expired. | Stop polling; start again with /device-authorize. |
invalid_request | The deviceCode is malformed, unknown, or already consumed. | Stop polling; start a new flow if appropriate. |
server_error | Token issuance failed after approval. | Stop polling and report a retryable service failure. |
Successful responses use Sudomimus’s normal camelCase JSON shape. Polling failures intentionally use the device-flow error vocabulary so public clients can follow the familiar device-code state machine.
Expiry and single use
Section titled “Expiry and single use”Each device authorization session is short lived. The production default is currently expiresIn: 600 seconds, but clients should use the value returned by /device-authorize instead of hard-coding a lifetime.
Once /device-token succeeds, the session is consumed. Repeating the same /device-token request with the same deviceCode returns invalid_request and cannot mint another token pair.
Code handling
Section titled “Code handling”Treat the two codes differently:
| Value | Who sees it | Purpose |
|---|---|---|
deviceCode | Only the initiating client | High-entropy bearer secret for /device-token |
userCode | The user and browser approval page | Short code the user compares and confirms |
Do not display deviceCode, put it in logs, embed it in a browser URL, or send it to your application backend unless that backend is the component polling /device-token. Losing deviceCode before expiry lets whoever holds it poll and consume the approved session.
userCode is safe to display, but it is not a token and cannot mint tokens by itself. It exists so the browser user can confirm they are approving the same client session shown in the terminal, launcher, or device UI.
No client secret
Section titled “No client secret”Device authorization is for public clients. /device-authorize does not require a client-auth JWT because the client could not protect the signing key. Instead, Sudomimus gates the flow on application configuration:
- The
applicationAnchormust resolve to an enabled application. - The application must have an enabled Layer 3
DEVICE_CODEReturnRule. - Browser approval still runs through the application’s Layer 1 authentication rules.
- The realized account is still checked by Layer 2 before approval can complete.
If you do have a confidential backend that can protect a client-auth private key, Connect or Connect browser polling may be a better fit.
Claims and token operations
Section titled “Claims and token operations”/device-token returns the same kind of application access and refresh tokens as other Sudomimus flows. Claim sharing follows the application’s claim policy and the user’s grant state, just like Connect or Native direct-issue.
Device API has no refresh endpoint. After the initial exchange, use Connect:
connect-api POST /refreshconnect-api POST /logoutconnect-api POST /introspectconnect-api POST /revoke-all
See Managing sessions for token lifecycle calls and the Device API reference for exact request and response schemas.