|
| 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 (also known as Device Flow) is OAuth 2.0 extension that enables devices with no browser |
| 8 | +or limited input capability to obtain an access token. It enables users to authenticate devices with limited input capabilities, |
| 9 | +such as smart TVs, gaming consoles, or IoT devices, by delegating the authentication process to another device with a full browser |
| 10 | +(e.g., a smartphone or computer). |
| 11 | + |
| 12 | +This document provides an overview of the Device Authorization Grant, a step-by-step example of its implementation, configuration |
| 13 | +options, and guidance on creating custom user interfaces for the verification screen. |
| 14 | + |
| 15 | +## Overview of the Flow |
| 16 | + |
| 17 | +Here is the high-level overview for the Device Authorization Flow: |
| 18 | + |
| 19 | +1. The device requests to be authorized from the Authorization server. |
| 20 | +2. The user is instructed to visit a URL on a different device and is given a user code. |
| 21 | +3. On a different device the user, visits the URL, provides the user code, logs in and grants access to the device. |
| 22 | +4. The device polls the Authorization server. Once the user authenticates and grants access, an access token is returned that can |
| 23 | + be used to access the protected resource. |
| 24 | + |
| 25 | +### Step 1: Device Requests Authorization |
| 26 | + |
| 27 | +The user tries to log in in the limited input device. The device sends a POST request to the Authorization server to initiate the |
| 28 | +flow with the following parameters: |
| 29 | + |
| 30 | +- `client_id`: The ID of the client that is making the request. |
| 31 | +- `scope` (optional): The scope of the access request, which specifies what resources the requesting application can access. |
| 32 | + |
| 33 | +The Authorization server responds with the following information: |
| 34 | + |
| 35 | +- `device_code`: A unique code to identify the authorization request. |
| 36 | +- `user_code`: A code the user will enter at the verification URL. |
| 37 | +- `verification_uri`: The URL where the user can authorize the device. |
| 38 | +- `verification_uri_complete`: The URL where the user can authorize the device, with the user_code already filled in. |
| 39 | +- `expires_in`: The lifespan of the device code (in seconds). |
| 40 | +- `interval`: The polling interval (in seconds) for the client to check if the user has authorized the device. |
| 41 | + |
| 42 | +--- |
| 43 | + |
| 44 | +## Step 2: Display User Code and Verification URL |
| 45 | + |
| 46 | +The device shows the user the `user_code` and `verification_uri` it received from the OAuth server. |
| 47 | + |
| 48 | +The user visits the provided URL on a separate device (e.g., a smartphone) and enters the code. |
| 49 | + |
| 50 | +## Step 3: User Grants Permission |
| 51 | + |
| 52 | +Once the user enters the code, they are prompted to log in (if not already authenticated) and grant or deny permission to the |
| 53 | +client. After granting permission, the user is redirected to a page confirming successful login. |
| 54 | + |
| 55 | +## Step 4: Device Polls for the Access Token |
| 56 | + |
| 57 | +While the user is authorizing the device, the device polls the `token` endpoint of the Authorization server to check whether the |
| 58 | +user has completed the authorization process, by making a POST request with the following parameters: |
| 59 | + |
| 60 | +- `client_id`: The ID of the client that is making the request. |
| 61 | +- `device_code`: The device code received from the device authorization request. |
| 62 | +- `grant_type`: This should always be `urn:ietf:params:oauth:grant-type:device_code`. |
| 63 | + |
| 64 | +After the user grants permission, the Authorization server will respond with an access token. |
| 65 | + |
| 66 | +## Configuration Options |
| 67 | + |
| 68 | +### Configuring the UI |
| 69 | + |
| 70 | +To enable and configure the Device Authorization Grant in Hydra, adjust the following settings in your Hydra configuration file: |
| 71 | + |
| 72 | +``` |
| 73 | +urls: |
| 74 | + device: |
| 75 | + verification: http://path/to/device/verification/ui |
| 76 | + success: http://path/to/device/success |
| 77 | +``` |
| 78 | + |
| 79 | +### Configuring user_code entropy |
| 80 | + |
| 81 | +Depending on your security needs and your traffic load, you may wish to enhance your user_code entropy. The hydra |
| 82 | +`oauth2.device_authorization.user_code_entropy` configuration supports 3 values: |
| 83 | + |
| 84 | +- `high`: user_code is 8 characters long and consists of alphanumeric characters, excluding some ambiguous symbols |
| 85 | +- `medium`: user_code is 8 characters long and consists only of upper case letter |
| 86 | +- `low`: user_code is 9 characters long and consists of numbers |
| 87 | + |
| 88 | +Keep in mind that higher entropy may make it harder for the user to enter the user_code. |
| 89 | + |
| 90 | +## Device Verification UI implementation |
| 91 | + |
| 92 | +Here is a sample implementation for a device verification UI : |
| 93 | + |
| 94 | +```js |
| 95 | +import { Configuration, OAuth2Api } from "@ory/client" |
| 96 | +import { Request, Response } from "express" |
| 97 | + |
| 98 | +const ory = new OAuth2Api( |
| 99 | + new Configuration({ |
| 100 | + basePath: `https://${process.env.ORY_PROJECT_SLUG}.projects.oryapis.com`, |
| 101 | + accessToken: process.env.ORY_API_KEY, |
| 102 | + }), |
| 103 | +) |
| 104 | + |
| 105 | +// Please note that this is an example implementation. |
| 106 | +// In a production app, please add proper error handling. |
| 107 | +export async function handleLogin(request: Request, response: Response) { |
| 108 | + const challenge = request.query.device_challenge.toString() |
| 109 | + const userCode = request.query.user_code.toString() |
| 110 | + |
| 111 | + // Show the login form if the form was not submitted. |
| 112 | + if (request.method === "GET") { |
| 113 | + response.render("device", { |
| 114 | + challenge, |
| 115 | + userCode, |
| 116 | + }) |
| 117 | + return |
| 118 | + } |
| 119 | + |
| 120 | + // User was authenticated successfully, |
| 121 | + return await ory |
| 122 | + .acceptUserCodeRequest({ |
| 123 | + deviceChallenge: challenge, |
| 124 | + acceptDeviceUserCodeRequest: { |
| 125 | + user_code: userCode, |
| 126 | + }, |
| 127 | + }) |
| 128 | + .then(({ redirect_to }) => { |
| 129 | + response.redirect(String(redirect_to)) |
| 130 | + }) |
| 131 | +} |
| 132 | +``` |
0 commit comments