OAuth device authorization
OAuth 2.0 Device Authorization Grant (RFC 8628) lets applications running in environments without browser access (such as SSH sessions, remote development environments, or constrained devices) authenticate with Buildkite. The device requests a code and polls for a token, while the user completes authorization in a browser on any device.
How it works
┌────────────┐ 1. POST /oauth/device_authorization ┌──────────────┐
│ │ ──────────────────────────────────────▶│ │
│ Device │ ◀──────────────────────────────────────│ Buildkite │
│ │ device_code + user_code │ │
│ │ └──────────────┘
│ │ 2. Display user_code to user
│ │ User visits verification_uri ┌──────────────┐
│ │ and enters user_code ▶│ Browser │
│ │ │ (any device) │
│ │ └──────────────┘
│ │ 3. Poll POST /oauth/token ┌──────────────┐
│ │ ──────────────────────────────────────▶│ │
│ │ ◀──────────────────────────────────────│ Buildkite │
└────────────┘ access_token (once approved) └──────────────┘
-
Request a device code from
POST /oauth/device_authorization. -
Display the
user_codeto the user and direct them to theverification_urito enter the code and authorize the application in a browser. -
Poll
POST /oauth/tokenwith thedevice_codeat the specified interval until the user approves, denies, or the code expires.
Token request
While the user completes authorization, poll the token endpoint using the device_code:
Endpoint: POST https://buildkite.com/oauth/token
POST /oauth/token HTTP/1.1
Host: buildkite.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:device_code
&client_id=your-client-id
&device_code=GmRhmhcxfnZfIQFAcZx7VFMylYeXPOO5
Request parameters
| Parameter | Required | Description |
|---|---|---|
grant_type |
Yes | Must be urn:ietf:params:oauth:grant-type:device_code
|
client_id |
Yes | The client ID of your OAuth application |
device_code |
Yes | The device_code from the device authorization response |
Successful response
Once the user approves the request, the token endpoint returns:
{
"access_token": "bkua_...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "...",
"scope": "read_user read_organizations"
}
Use the access_token value in the Authorization header for API requests:
Authorization: Bearer bkua_...
Polling errors
While waiting for user approval, the token endpoint returns error responses until the user acts. Poll at the interval specified in the device authorization response and handle these errors:
error |
Description | Action |
|---|---|---|
authorization_pending |
The user has not yet approved or denied the request | Continue polling at the current interval |
slow_down |
Polling too frequently | Increase the polling interval by 5 seconds and continue polling |
access_denied |
The user denied the authorization request | Stop polling and inform the user |
expired_token |
The device code has expired | Stop polling. Request a new device code to restart the flow |
invalid_grant |
The device code is invalid or has already been used | Stop polling |
The initial polling interval is 5 seconds. Each slow_down response increases the required interval by 5 seconds. Respect the interval to avoid repeated slow_down responses.
Available scopes
Device authorization tokens support the same scopes as Buildkite API access tokens.
Troubleshooting
The device authorization and token endpoints return error responses with an error code and optional error_description:
{
"error": "invalid_client"
}
Common errors
error |
Fix |
|---|---|
invalid_client |
Check that the client_id is correct and the application is enabled. Confidential clients must also provide a valid client_secret
|
invalid_scope |
Ensure all requested scopes are valid. An empty or missing scope parameter is rejected |
server_error |
The device authorization service is temporarily unavailable. Retry later |