|
| 1 | +--- |
| 2 | +title: Device Authorization |
| 3 | +description: Device authorization flow for TVs, consoles, CLIs, and other limited-input clients. |
| 4 | +--- |
| 5 | + |
| 6 | +The `DeviceAuthorizationPlugin` implements a device authorization flow for clients that cannot easily complete an interactive sign-in flow, such as TVs, game consoles, smart displays, and terminal apps. |
| 7 | + |
| 8 | +When enabled, the plugin issues a short `user_code` plus a longer `device_code`, lets a signed-in user approve or deny the request on another device, and returns a Better Auth session token from the polling endpoint once approved. |
| 9 | + |
| 10 | +## Setup |
| 11 | + |
| 12 | +```rust |
| 13 | +use better_auth::plugins::DeviceAuthorizationPlugin; |
| 14 | + |
| 15 | +let auth = BetterAuth::new(config) |
| 16 | + .database(database) |
| 17 | + .plugin( |
| 18 | + DeviceAuthorizationPlugin::new() |
| 19 | + .enabled(true) |
| 20 | + .verification_uri("/device") |
| 21 | + .interval(5) |
| 22 | + .expires_in(1800) |
| 23 | + ) |
| 24 | + .build() |
| 25 | + .await?; |
| 26 | +``` |
| 27 | + |
| 28 | +### Configuration |
| 29 | + |
| 30 | +| Option | Type | Default | Description | |
| 31 | +|--------|------|---------|-------------| |
| 32 | +| `enabled` | `bool` | `false` | Enables the device authorization endpoints | |
| 33 | +| `verification_uri` | `String` | `"/device"` | URL or path the user should open to enter the `user_code` | |
| 34 | +| `interval` | `i64` | `5` | Minimum polling interval in seconds for `/device/token` | |
| 35 | +| `expires_in` | `i64` | `1800` | Lifetime in seconds for the device authorization request | |
| 36 | + |
| 37 | +<Callout type="info"> |
| 38 | +`verification_uri` is returned to the device client exactly as configured. In practice, this should usually point to a user-facing page in your app where the user can sign in and submit the `userCode`. |
| 39 | +</Callout> |
| 40 | + |
| 41 | +## How It Works |
| 42 | + |
| 43 | +### Device Flow |
| 44 | + |
| 45 | +1. The device client calls `POST /device/code` with a `client_id` and optional `scope`. |
| 46 | +2. The API returns `device_code`, `user_code`, `verification_uri`, `expires_in`, and `interval`. |
| 47 | +3. The user opens `verification_uri` on another device, signs in if needed, and enters the `user_code`. |
| 48 | +4. Your verification UI calls `POST /device/approve` or `POST /device/deny` with the `userCode`. |
| 49 | +5. The original device polls `POST /device/token` with the `device_code` until the request is approved or denied. |
| 50 | +6. On approval, `/device/token` returns an `access_token` containing a Better Auth session token. |
| 51 | + |
| 52 | +The optional `scope` value is stored with the device authorization record so applications can track the requested scope, but the plugin currently creates a standard Better Auth session when the request is approved. |
| 53 | + |
| 54 | +## API Endpoints |
| 55 | + |
| 56 | +The Device Authorization plugin exposes 4 endpoints. The request and response shapes documented below are the current reference for this plugin. |
| 57 | + |
| 58 | +| Endpoint | Method | Auth | Description | |
| 59 | +|----------|--------|------|-------------| |
| 60 | +| `/device/code` | POST | No | Issue a new `device_code` and `user_code` | |
| 61 | +| `/device/token` | POST | No | Poll for approval and exchange the `device_code` for a session token | |
| 62 | +| `/device/approve` | POST | Yes | Approve a pending device authorization request | |
| 63 | +| `/device/deny` | POST | Yes | Deny a pending device authorization request | |
| 64 | + |
| 65 | +### Request and Response Shapes |
| 66 | + |
| 67 | +Create a device code: |
| 68 | + |
| 69 | +```json |
| 70 | +{ |
| 71 | + "client_id": "living-room-tv", |
| 72 | + "scope": "openid profile" |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +Example response: |
| 77 | + |
| 78 | +```json |
| 79 | +{ |
| 80 | + "device_code": "a-long-random-device-code", |
| 81 | + "user_code": "AB12CD34", |
| 82 | + "verification_uri": "/device", |
| 83 | + "expires_in": 1800, |
| 84 | + "interval": 5 |
| 85 | +} |
| 86 | +``` |
| 87 | + |
| 88 | +Approve from a signed-in browser session: |
| 89 | + |
| 90 | +```json |
| 91 | +{ |
| 92 | + "userCode": "AB12CD34" |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +Successful token exchange: |
| 97 | + |
| 98 | +```json |
| 99 | +{ |
| 100 | + "access_token": "session_..." |
| 101 | +} |
| 102 | +``` |
| 103 | + |
| 104 | +## Building the Verification Page |
| 105 | + |
| 106 | +The plugin provides the backend endpoints, but you still need a small verification UI in your app: |
| 107 | + |
| 108 | +1. Render a page at the same URL you use for `verification_uri`. |
| 109 | +2. Let the user sign in if they do not already have a session. |
| 110 | +3. Collect the `userCode` shown on the device. |
| 111 | +4. Call `POST /device/approve` or `POST /device/deny` with `{ "userCode": "..." }`. |
| 112 | + |
| 113 | +Because approval and denial require a valid Better Auth session, the verification page should run in a browser or app context where the user can authenticate normally. |
| 114 | + |
| 115 | +## Polling Behavior |
| 116 | + |
| 117 | +The `/device/token` endpoint uses the current device authorization state to guide the client: |
| 118 | + |
| 119 | +| Status | Condition | |
| 120 | +|--------|-----------| |
| 121 | +| `200` | Request approved, returns `{ "access_token": "session_..." }` | |
| 122 | +| `400 authorization_pending` | The user has not approved or denied the request yet | |
| 123 | +| `400 slow_down` | The client polled faster than the configured `interval` | |
| 124 | +| `400 access_denied` | The user explicitly denied the request | |
| 125 | +| `400 invalid_grant` | The `device_code` is unknown, expired, or has already been consumed | |
| 126 | + |
| 127 | +Once a device code is successfully exchanged, it is consumed and cannot be reused. |
| 128 | + |
| 129 | +## Errors |
| 130 | + |
| 131 | +| Status | Condition | |
| 132 | +|--------|-----------| |
| 133 | +| `401` | `/device/approve` or `/device/deny` was called without a valid session | |
| 134 | +| `404` | The supplied `userCode` was not found | |
| 135 | +| `404` | The plugin is disabled and the device endpoints are not available | |
0 commit comments