---
title: Device authorization flow
description: Use the Device API to sign in CLIs, launchers, and other public
  clients through a browser-confirmed user code.
editUrl: true
head: []
template: doc
sidebar:
  order: 1
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

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)](https://www.rfc-editor.org/rfc/rfc8628) 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

| 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

The client starts by posting its application anchor:

```bash
curl -X POST https://device-api.sudomimus.com/device-authorize \
  -H "Content-Type: application/json" \
  -d '{
    "applicationAnchor": "your-application"
  }'
```

Successful response:

```json
{
  "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

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

```text
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:

```text
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.

## 3. Poll for tokens

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

```bash
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:

```json
{
  "error": "authorization_pending"
}
```

After approval, the same endpoint returns ordinary Sudomimus application tokens:

```json
{
  "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

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](/en-us/guides/managing-sessions/) for those operations and [Device polling and errors](/en-us/device/polling-and-errors/) for the polling state machine.

## 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

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](/en-us/native/overview/#browser-polling) instead when you have a confidential application backend that can sign `/establish`. Use [Native direct-issue](/en-us/native/overview/) 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](/en-us/api/device/).