Device Authorization
Approve CLI, TV, and limited-input device sign-ins with Solid and Zaidan.
The Device Authorization plugin adds the browser half of Better Auth's device authorization flow. A user enters the short code shown by a CLI, TV, or another limited-input device, signs in if needed, then approves or denies access.
It contributes:
- A copied
<DeviceAuthorization />view at/auth/device - Code verification with the
user_codequery parameter prefilled when present - Sign-in redirection that preserves the pending code
- Approve and deny confirmation states
- Solid Query mutation options for verifying, approving, and denying requests
The requesting device remains responsible for calling Better Auth's /device/code endpoint and polling /device/token.
Setup
Configure the Better Auth server
Add the Device Authorization plugin to your Better Auth server. Set verificationUri to the public route that renders the UI view:
import { betterAuth } from "better-auth"
import { deviceAuthorization } from "better-auth/plugins"
export const auth = betterAuth({
// ...
plugins: [
deviceAuthorization({
verificationUri: "/auth/device"
})
]
})Generate or migrate your Better Auth schema after enabling the plugin:
bunx auth@latest migrateThe plugin adds the deviceCode model used to track pending requests.
Configure the Solid client
Add deviceAuthorizationClient() to the auth client:
import { createAuthClient } from "@better-auth-ui/solid"
import { deviceAuthorizationClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
plugins: [deviceAuthorizationClient()]
})Install the Solid and Zaidan view
bunx --bun shadcn@latest add https://better-auth-ui.com/r/solid/device-authorization.jsonThis copies the following files into your project:
src/lib/auth/device-authorization-plugin.tssrc/components/auth/device-authorization/device-authorization.tsx- Local Zaidan UI primitives under
src/components/ui/**
After install, the view and plugin factory belong to your application. You can adapt their layout or behavior without waiting for a package release.
Register the UI plugin
Pass deviceAuthorizationPlugin() to the copied <AuthProvider>:
import { AuthProvider } from "@/components/auth/auth-provider"
import { deviceAuthorizationPlugin } from "@/lib/auth/device-authorization-plugin"
<AuthProvider
authClient={authClient}
plugins={[deviceAuthorizationPlugin()]}
>
{children}
</AuthProvider>Allow the device route
Include the plugin path in the route that renders <Auth />. Keep it aligned with the server's verificationUri:
import { viewPaths } from "@better-auth-ui/core"
import { createFileRoute, redirect } from "@tanstack/solid-router"
import { Auth } from "@/components/auth/auth"
import { deviceAuthorizationPlugin } from "@/lib/auth/device-authorization-plugin"
const validAuthPathSegments = new Set([
...Object.values(viewPaths.auth),
deviceAuthorizationPlugin().viewPaths.auth.deviceAuthorization
])
export const Route = createFileRoute("/auth/$path")({
beforeLoad({ params: { path } }) {
if (!validAuthPathSegments.has(path)) {
throw redirect({ to: "/" })
}
},
component: AuthPage
})
function AuthPage() {
const { path } = Route.useParams()()
return <Auth path={path} />
}Component
The copied component is rendered automatically at /auth/device when the plugin is registered. You can also render it directly:
import { DeviceAuthorization } from "@/components/auth/device-authorization/device-authorization"
<DeviceAuthorization />Options
deviceAuthorizationPlugin({
// Override the URL segment. Default: "device"
path: "activate",
// Match Better Auth's server-side userCodeLength. Default: 8
userCodeLength: 8,
localization: {
approveDevice: "Allow this device?"
}
})Keep userCodeLength equal to the value passed to Better Auth's server plugin. A mismatched length prevents valid codes from being submitted.
Localization
Solid APIs
The copied view uses these Solid Query option factories:
verifyDeviceCodeOptionsverifies and claims the submitted code for the current session.approveDeviceOptionsgrants the requesting device access.denyDeviceOptionsrejects the request.
Sessions and revocation
An approved device token creates an ordinary Better Auth session. There is no separate device registry in the Device Authorization plugin. Use <ActiveSessions /> to list sessions and revoke access for an approved device.
Last updated on