Better Auth in Rust

Device Authorization

Device authorization flow for TVs, consoles, CLIs, and other limited-input clients.

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.

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.

Setup

use better_auth::plugins::DeviceAuthorizationPlugin;

let auth = BetterAuth::new(config)
    .database(database)
    .plugin(
        DeviceAuthorizationPlugin::new()
            .enabled(true)
            .verification_uri("/device")
            .interval(5)
            .expires_in(1800)
    )
    .build()
    .await?;

Configuration

OptionTypeDefaultDescription
enabledboolfalseEnables the device authorization endpoints
verification_uriString"/device"URL or path the user should open to enter the user_code
intervali645Minimum polling interval in seconds for /device/token
expires_ini641800Lifetime in seconds for the device authorization request

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.

How It Works

Device Flow

  1. The device client calls POST /device/code with a client_id and optional scope.
  2. The API returns device_code, user_code, verification_uri, expires_in, and interval.
  3. The user opens verification_uri on another device, signs in if needed, and enters the user_code.
  4. Your verification UI calls POST /device/approve or POST /device/deny with the userCode.
  5. The original device polls POST /device/token with the device_code until the request is approved or denied.
  6. On approval, /device/token returns an access_token containing a Better Auth session token.

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.

API Endpoints

The Device Authorization plugin exposes 4 endpoints. The request and response shapes documented below are the current reference for this plugin.

EndpointMethodAuthDescription
/device/codePOSTNoIssue a new device_code and user_code
/device/tokenPOSTNoPoll for approval and exchange the device_code for a session token
/device/approvePOSTYesApprove a pending device authorization request
/device/denyPOSTYesDeny a pending device authorization request

Request and Response Shapes

Create a device code:

{
  "client_id": "living-room-tv",
  "scope": "openid profile"
}

Example response:

{
  "device_code": "a-long-random-device-code",
  "user_code": "AB12CD34",
  "verification_uri": "/device",
  "expires_in": 1800,
  "interval": 5
}

Approve from a signed-in browser session:

{
  "userCode": "AB12CD34"
}

Successful token exchange:

{
  "access_token": "session_..."
}

Building the Verification Page

The plugin provides the backend endpoints, but you still need a small verification UI in your app:

  1. Render a page at the same URL you use for verification_uri.
  2. Let the user sign in if they do not already have a session.
  3. Collect the userCode shown on the device.
  4. Call POST /device/approve or POST /device/deny with { "userCode": "..." }.

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.

Polling Behavior

The /device/token endpoint uses the current device authorization state to guide the client:

StatusCondition
200Request approved, returns { "access_token": "session_..." }
400 authorization_pendingThe user has not approved or denied the request yet
400 slow_downThe client polled faster than the configured interval
400 access_deniedThe user explicitly denied the request
400 invalid_grantThe device_code is unknown, expired, or has already been consumed

Once a device code is successfully exchanged, it is consumed and cannot be reused.

Errors

StatusCondition
401/device/approve or /device/deny was called without a valid session
404The supplied userCode was not found
404The plugin is disabled and the device endpoints are not available

On this page