Device Authorization Grant (RFC 8628)¶
Overview¶
JustIAM supports the OAuth 2.0 Device Authorization Grant (RFC 8628), also known as the Device Flow. This grant type is designed for input-constrained devices (smart TVs, CLI tools, IoT devices) that cannot easily open a browser or securely handle redirects.
Typical use cases:
- CLI tools authenticating on behalf of the user (e.g., Terraform providers,
kubectlplugins) - Devices with limited or no keyboard input
- Headless clients running in terminals
Endpoints¶
| Endpoint | Method | Description |
|---|---|---|
/oauth2/device_authorization |
POST | Start the device flow — returns device and user codes |
/device |
GET | User-facing portal to enter the device code |
/device |
POST | Submit the code and approve or deny access |
/oauth2/token |
POST | Device polls this endpoint until the user approves |
Flow¶
Device JustIAM User's Browser
| | |
|-- POST /oauth2/device_auth -->| |
|<-- device_code, user_code ----| |
| | |
| (display user_code to user) | |
| |<-- GET /device?user_code=... -|
| |--- HTML form (code entry) --> |
| |<-- POST /device (approve) ----|
| |--- "Access approved" -------> |
| | |
|-- POST /oauth2/token -------->| |
| (polling with device_code) | |
|<-- access_token, id_token ----| |
Step 1 — Request device and user codes¶
POST /api/v1/oauth2/device_authorization
Content-Type: application/x-www-form-urlencoded
client_id=my-cli-tool&scope=openid+profile+email
Response:
{
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
"user_code": "BCDF-HJKM",
"verification_uri": "https://justiam.example.com/device",
"verification_uri_complete": "https://justiam.example.com/device?user_code=BCDF-HJKM",
"expires_in": 300,
"interval": 5
}
The device should display the user_code and verification_uri to the user, or render a QR code using verification_uri_complete.
Step 2 — User activates the device¶
The user navigates to the verification_uri in their browser, logs in, and enters the user_code. JustIAM shows a confirmation page with the application name and requested scopes. The user approves or denies.
Step 3 — Device polls for a token¶
The device polls POST /api/v1/oauth2/token every interval seconds until it receives a token or a terminal error:
POST /api/v1/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:device_code
&device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS
&client_id=my-cli-tool
Possible responses while polling:
| HTTP status | error field |
Meaning |
|---|---|---|
| 400 | authorization_pending |
User hasn't actioned yet — keep polling |
| 400 | slow_down |
Polling too fast — increase interval |
| 400 | access_denied |
User denied access — stop |
| 400 | expired_token |
Device code expired (> 5 min) — restart |
| 200 | — | Approved — response contains access_token and id_token |
Discovery¶
The device authorization endpoint is advertised in the OIDC discovery document:
{
"device_authorization_endpoint": "https://justiam.example.com/api/v1/oauth2/device_authorization"
}
Application configuration¶
Applications using the Device Authorization Grant must have urn:ietf:params:oauth:grant-type:device_code in their grant_types. Public clients (no client secret) are supported and recommended for CLI tools.
Terraform example:
resource "justiam_application" "cli_tool" {
name = "my-cli-tool"
friendly_name = "My CLI Tool"
type = "web"
client_id = "my-cli-tool"
grant_types = ["urn:ietf:params:oauth:grant-type:device_code"]
allowed_scopes = ["openid", "profile", "email"]
is_public = true
is_active = true
}
See the full working example at terraform-provider-justiam/examples/modular/applications/device_authorization_cli_0001.tf.
Security considerations¶
- Device codes expire after 5 minutes by default.
- User codes use an unambiguous alphabet (
BCDFGHJKLMNPQRSTVWXYZ) to avoid confusion between similar-looking characters (0,O,1,I,L). - The device code is a 32-byte cryptographically random token; the user code is short and human-typeable (format:
XXXX-YYYY). - Only the user who owns the session at the time of portal approval can approve the request —
access_restrictedgroup membership rules apply. - Confidential clients must present their
client_secretwhen polling for a token.