Use OAuth Device Authorization Grant, Beta
OAuth 2.0 Device Authorization Grant lets a user authorize a device or application that cannot open a browser or easily accept text input. It is commonly used by command-line tools, TVs, game consoles, and other input-constrained devices.
The device displays a short user code and a verification URL. The user opens the URL on a second device, signs in to Clerk, reviews the requested access, and approves or denies the request. While the user completes that step, the original device polls Clerk until it can receive tokens or the request ends.
How the flow works
- The device requests a device code from Clerk's
/oauth/device_authorizationendpoint. - Clerk returns a private
device_code, a shortuser_code, verification URLs, an expiry, and a minimum polling interval. - The device shows the user the
user_codeandverification_uri. It can also turnverification_uri_completeinto a link or QR code. - The user opens the verification page in a browser, signs in, reviews the OAuth application and scopes, and approves or denies access.
- The device polls
/oauth/tokenat the required interval. After approval, Clerk returns an and refresh token. If the client requested theopenidscope, Clerk also returns an ID token.
Both the device_code and user_code expire after 10 minutes. A device_code can be exchanged only once.
Configure an OAuth application
Device Authorization Grant must be enabled for each OAuth application that uses it. To do so, navigate to the OAuth applications page in the Clerk Dashboard, create or select an application, and enable Device authorization grant. You can also configure the application through the Clerk Backend API using the Clerk CLI.
For a public client, set public to true. Public clients identify themselves with their Client ID and do not send a Client Secret:
npx clerk@latest api oauth_applications -d '{
"name": "Living room app",
"scopes": "openid profile email offline_access",
"public": true,
"device_authorization_grant_enabled": true
}'To enable Device Authorization Grant for an existing application, pass its OAuth application ID:
npx clerk@latest api oauth_applications/<OAUTH_APPLICATION_ID> \
-X PATCH \
-d '{"device_authorization_grant_enabled":true}'Start a device authorization request
Send a form-encoded POST request to the device_authorization_endpoint advertised in Clerk's metadata. The examples in this guide use your Clerk . A public client sends its Client ID without a Client Secret:
curl "https://YOUR_FRONTEND_API_URL/oauth/device_authorization" \
-X POST \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<OAUTH_CLIENT_ID>' \
--data-urlencode 'scope=openid profile email offline_access'A confidential client must also authenticate. HTTP Basic authentication is recommended:
curl "https://YOUR_FRONTEND_API_URL/oauth/device_authorization" \
-X POST \
-u '<OAUTH_CLIENT_ID>:<OAUTH_CLIENT_SECRET>' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<OAUTH_CLIENT_ID>' \
--data-urlencode 'scope=openid profile email offline_access'The requested scopes must be assigned to the OAuth application. You can also send an OpenID Connect nonce; when present, it must contain at least eight characters.
A successful request returns a response with this structure:
{
"device_code": "5FZ4RVGZ8QW3HJ7KM2NP9TXC6BD1YS0AE5RGH4KJVQW",
"user_code": "BCDF-GHJK",
"verification_uri": "https://accounts.example.com/device",
"verification_uri_complete": "https://accounts.example.com/device?user_code=BCDF-GHJK",
"expires_in": 600,
"interval": 5
}- Keep
device_codeprivate. The device uses it to poll the token endpoint and must never show it to the user. - Show
user_codeandverification_uritogether so the user can complete the flow manually. - Use
verification_uri_completefor a convenient link or QR code that pre-fills the user code. Do not make it the only way to continue. - Treat
expires_inandintervalas authoritative. Do not hardcode their current values.
Poll the token endpoint
Wait at least the number of seconds specified by interval between requests to /oauth/token. Public clients must include their Client ID:
curl "https://YOUR_FRONTEND_API_URL/oauth/token" \
-X POST \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=<OAUTH_CLIENT_ID>' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \
--data-urlencode 'device_code=<DEVICE_CODE>'A confidential client authenticates the token request with its Client ID and Client Secret:
curl "https://YOUR_FRONTEND_API_URL/oauth/token" \
-X POST \
-u '<OAUTH_CLIENT_ID>:<OAUTH_CLIENT_SECRET>' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \
--data-urlencode 'device_code=<DEVICE_CODE>'Keep polling only while the request is pending:
For any other OAuth error, including invalid_grant or invalid_client, stop polling and surface a useful retry or configuration message. Network failures can be retried with backoff while the device code is still valid.
After the user approves the request, the token endpoint returns the same token response shape as Clerk's other OAuth grants. Store access and refresh tokens using the secure storage available on the device. To use the access token with your API, see Verify OAuth tokens.
User verification
By default, Clerk hosts the verification page in the Account Portal. The page lets the user enter or confirm the user code, displays the requesting OAuth application and scopes, and provides equally visible approve and deny actions.
When the application requests user:org:read, the verification page also lets the user select an Organization. Clerk includes the selected Organization's ID as the org_id claim in the access token. If the client also requested the openid scope, Clerk includes org_id in the ID token.
Discover Device Authorization Grant support
OAuth clients can retrieve Clerk's metadata from either of these endpoints on your Clerk :
https://<YOUR_FRONTEND_API_URL>/.well-known/oauth-authorization-serverhttps://<YOUR_FRONTEND_API_URL>/.well-known/openid-configuration
When Device Authorization Grant is available and the verification page is reachable, a sample metadata document includes:
{
"device_authorization_endpoint": "https://YOUR_FRONTEND_API_URL/oauth/device_authorization",
"grant_types_supported": [
"authorization_code",
"refresh_token",
"urn:ietf:params:oauth:grant-type:device_code"
]
}Clients should use the advertised endpoint instead of constructing it from the issuer URL.
Feedback
Last updated on