Skip to content

Commit 90b4ac2

Browse files
nsklikasunatasha8zepatrikvinckr
authored
docs: add device flow documentation (#2026)
* docs: add device flow documentation * chore: Refine device verification UI section wording * chore: Update user code entropy configuration details Clarified the description of user code entropy options and their implications for user entry. * chore: Revise Device Authorization Grant documentation Updated the description and steps for the Device Authorization Grant to clarify the process and correct terminology. * chore: Update device authorization flow steps and formatting * chore: Added image for device authorization flow Added an image to illustrate the device authorization flow. * chore: Fix image path for device authorization flow * chore: Integrate Mermaid diagram for device authorization flow Added a sequence diagram to illustrate the device authorization flow using Mermaid. * Update docs/oauth2-oidc/device-authorization.mdx Co-authored-by: Patrik <zepatrik@users.noreply.github.com> * Update docs/oauth2-oidc/device-authorization.mdx Co-authored-by: Patrik <zepatrik@users.noreply.github.com> * Update docs/oauth2-oidc/device-authorization.mdx Co-authored-by: Patrik <zepatrik@users.noreply.github.com> * Update docs/oauth2-oidc/device-authorization.mdx Co-authored-by: Patrik <zepatrik@users.noreply.github.com> * Update docs/oauth2-oidc/device-authorization.mdx Co-authored-by: Patrik <zepatrik@users.noreply.github.com> * Update docs/oauth2-oidc/device-authorization.mdx Co-authored-by: Patrik <zepatrik@users.noreply.github.com> * chore: address review comments and format * chore: add to sidebar * chore: fix grammar and typos --------- Co-authored-by: unatasha8 <una.cogavin@ory.sh> Co-authored-by: Patrik <zepatrik@users.noreply.github.com> Co-authored-by: vinckr <vincent@ory.sh>
1 parent 71b9950 commit 90b4ac2

File tree

2 files changed

+185
-0
lines changed

2 files changed

+185
-0
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
---
2+
id: device-authorization
3+
title: Device Authorization
4+
sidebar_label: Device authorization flow
5+
---
6+
7+
The OAuth 2.0 Device Authorization Grant (RFC 8628) brings OAuth to devices with internet connectivity but limited input
8+
capabilities. This flow is designed for smart TVs, streaming devices, IoT hardware, printers, remote terminal sessions, AI agents,
9+
and other connected devices where typing credentials or opening a browser isn't practical or possible. Here's how it works: the
10+
device to be authenticated displays a URL and a short code, prompting you to open that URL on your phone or computer to authorize
11+
access. After successful authorization, the device will get an access and (optionally) a refresh token. The two devices don't need
12+
to communicate directly; the authorization happens through the OAuth provider.
13+
14+
This document provides an overview of the Ory's device authorization grant flow, with a step-by-step example of its
15+
implementation, configuration options, and guidance on creating custom user interfaces for the verification screen.
16+
17+
## Overview of the flow
18+
19+
Here is the high-level overview for the device authorization grant flow:
20+
21+
1. The user attempts to log in to the device. This initiates the device to request authorization from the authorization server.
22+
1. When the authorization server responds, the user is instructed to visit a URL and enter the provided user code, which they do
23+
on a different device.
24+
1. On the different device the user visits the URL, enters the user code, logs in, and grants access to the device.
25+
1. In the meantime, the device polls the authorization server. Once the user authenticates and grants access, the authentication
26+
server sends an access token to the device, which is used to access the protected resource.
27+
28+
```mdx-code-block
29+
import Mermaid from "@site/src/theme/Mermaid";
30+
31+
<Mermaid
32+
chart={`sequenceDiagram
33+
participant D as Device
34+
participant U as User
35+
participant AS as OAuth2 Server
36+
37+
activate D
38+
D->>+AS: Start device code grant
39+
AS-->>-D: Verification URI, Device-code, User-code
40+
loop background poll before user authorized
41+
D->>+AS: Request Token by device code
42+
AS-->>-D: Error
43+
end
44+
D->>+U: Ask visit verification URI<br/>Reveal User-code
45+
U->>+AS: Request verification URI
46+
AS-->>-U: Prompt for User-code
47+
U->>+AS: Sumbit User-code
48+
AS-->>-U: Prompt for login and consent
49+
U->>+AS: Submit credentials and consent
50+
AS-->>-U: Show success
51+
deactivate U
52+
loop background poll after user authorized
53+
D->>+AS: Request Token by device code
54+
end
55+
AS-->>-D: Token
56+
D-->>D: Process and store token
57+
deactivate D
58+
`} />
59+
```
60+
61+
### Step 1: Device requests authorization
62+
63+
The user attempts to log in through the limited input device. The device sends a POST request to the authorization server to
64+
initiate the flow with the following parameters:
65+
66+
- `client_id`: The ID of the client (device) that's making the request
67+
- `scope` (optional): The scope of the access request, which specifies which resources the requesting device can access
68+
69+
The authorization server responds with the following information:
70+
71+
- `device_code`: A unique code to identify the authorization request
72+
- `user_code`: A code the user enters at the verification URL
73+
- `verification_uri`: The URL where the user authorizes the device
74+
- `verification_uri_complete`: The URL where the user authorizes the device, with the user_code already filled in
75+
- `expires_in`: The lifespan of the device code (in seconds)
76+
- `interval`: The polling interval (in seconds) for the client to check if the user has authorized the device yet
77+
78+
### Step 2: Display user code and verification URI
79+
80+
The device shows the user the `user_code` and `verification_uri` it received from the authorization server. Depending on the
81+
device, this can be in the form of a URL, QR code, acoustically, or any other form that the device can communicate with the user.
82+
83+
### Step 3: User grants permission
84+
85+
The user visits the provided URI on a separate device, such as a phone, and enters the code. Once the user enters the code, the
86+
user is prompted to log in, if not already authenticated, and grants or denies permission to the client (device). After granting
87+
permission, the user is redirected to a page confirming they are successfully logged in.
88+
89+
### Step 4: Device polls for the access token
90+
91+
While the user is authorizing the device, the device polls the `token` endpoint of the authorization server to check whether the
92+
user has completed the authorization process by making a POST request with the following parameters:
93+
94+
- `client_id`: The ID of the client that's making the request
95+
- `device_code`: The device code returned from the authorization request
96+
- `grant_type`: This must always be `urn:ietf:params:oauth:grant-type:device_code`
97+
98+
After the user grants their consent, the authentication server sends an access token to the device, which is used to access the
99+
protected resource.
100+
101+
## Configuration options
102+
103+
### Configure the user interface
104+
105+
To enable and configure the device authorization grant in Ory Hydra, adjust the following settings in your configuration file:
106+
107+
```yaml
108+
urls:
109+
device:
110+
# The verification UI is where the user inputs the user-code
111+
verification: http://path/to/device/verification/ui
112+
# The success UI is where the user is sent to after successful authorization
113+
success: http://path/to/device/success
114+
```
115+
116+
### Configure user code entropy
117+
118+
Depending on your security needs and your traffic load, you should choose the appropriate `user_code` entropy. The
119+
`oauth2.device_authorization.user_code.entropy_preset` configuration supports 3 values:
120+
121+
- `high`: `user_code` is 8 characters long and consists of alphanumeric characters, excluding some ambiguous symbols
122+
- `medium`: `user_code` is 8 characters long and consists of only upper case alphabetic characters
123+
- `low`: `user_code` is 9 characters long and consists of only numeric characters
124+
125+
It is also possible to configure the length and character set directly:
126+
127+
```yaml
128+
oauth2:
129+
device_authorization:
130+
user_code:
131+
length: 8
132+
character_set: abcdefghijklmnopqrstuvwxyz0123456789
133+
```
134+
135+
It is important to strike the right balance between security and user experience here. Higher entropy enhances security and
136+
protects against an attacker randomly guessing valid user-codes. This is especially important when more concurrent device flows
137+
are being performed. As users will need to manually enter the user code, the higher the entropy, the more difficult it will be for
138+
the user to enter the user code. For a better user experience, ambiguous characters should be avoided, for example `O` and `0` on
139+
any display, or `1` and `7` on a 7-segment display. This isn't of any concern when the user doesn't need to input the user-code
140+
manually, for example when scanning a QR code.
141+
142+
## Device verification UI implementation
143+
144+
Here is a sample UI implementation for device verification:
145+
146+
```js
147+
import { Configuration, OAuth2Api } from "@ory/client"
148+
import { Request, Response } from "express"
149+
150+
const ory = new OAuth2Api(
151+
new Configuration({
152+
basePath: `https://${process.env.ORY_PROJECT_SLUG}.projects.oryapis.com`,
153+
accessToken: process.env.ORY_API_KEY,
154+
}),
155+
)
156+
157+
// Please note that this is an example implementation.
158+
// In a production app, please add proper error handling.
159+
export async function handleLogin(request: Request, response: Response) {
160+
const challenge = request.query.device_challenge.toString()
161+
const userCode = request.query.user_code.toString()
162+
163+
// Show the login form if the form was not submitted.
164+
if (request.method === "GET") {
165+
response.render("device", {
166+
challenge,
167+
userCode,
168+
})
169+
return
170+
}
171+
172+
// User was authenticated successfully,
173+
return await ory
174+
.acceptUserCodeRequest({
175+
deviceChallenge: challenge,
176+
acceptDeviceUserCodeRequest: {
177+
user_code: userCode,
178+
},
179+
})
180+
.then(({ redirect_to }) => {
181+
response.redirect(String(redirect_to))
182+
})
183+
}
184+
```

src/sidebar.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ const hydra: SidebarItemsConfig = [
653653
items: [
654654
"oauth2-oidc/authorization-code-flow",
655655
"oauth2-oidc/client-credentials",
656+
"oauth2-oidc/device-authorization",
656657
"oauth2-oidc/resource-owner-password-grant",
657658
"oauth2-oidc/refresh-token-grant",
658659
"oauth2-oidc/userinfo-oidc",

0 commit comments

Comments
 (0)