|
| 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 | +such as 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 | +1. The user is instructed to visit a URL on a different device and is given a user code. |
| 21 | +1. On a different device the user, visits the URL, provides the user code, logs in and grants access to the device. |
| 22 | +1. 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 | +### 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 | +### Display user code and verification URI |
| 43 | + |
| 44 | +The device shows the user the `user_code` and `verification_uri` it received from the Authorization Server. |
| 45 | + |
| 46 | +The user visits the provided URI on a separate device, such as a smartphone, and enters the code. |
| 47 | + |
| 48 | +### User grants permission |
| 49 | + |
| 50 | +Once the user enters the code, they are prompted to log in, if not already authenticated, and grant or deny permission to the |
| 51 | +client. After granting permission, the user is redirected to a page confirming successful login. |
| 52 | + |
| 53 | +### Device polls for the access token |
| 54 | + |
| 55 | +While the user is authorizing the device, the device polls the `token` endpoint of the Authorization Server to check whether the |
| 56 | +user has completed the authorization process, by making a POST request with the following parameters: |
| 57 | + |
| 58 | +- `client_id`: The ID of the client that is making the request. |
| 59 | +- `device_code`: The device code received from the device authorization request. |
| 60 | +- `grant_type`: This should always be `urn:ietf:params:oauth:grant-type:device_code`. |
| 61 | + |
| 62 | +After the user grants permission, the Authorization Server will respond with an access token. |
| 63 | + |
| 64 | +## Configuration options |
| 65 | + |
| 66 | +### Configuring the user interface |
| 67 | + |
| 68 | +To enable and configure the Device Authorization Grant in Ory Hydra, adjust the following settings in your configuration file: |
| 69 | + |
| 70 | +``` |
| 71 | +urls: |
| 72 | + device: |
| 73 | + verification: http://path/to/device/verification/ui |
| 74 | + success: http://path/to/device/success |
| 75 | +``` |
| 76 | + |
| 77 | +### Configuring user code entropy |
| 78 | + |
| 79 | +Depending on your security needs and your traffic load, you may wish to enhance your `user_code` entropy. The Ory Hydra |
| 80 | +`oauth2.device_authorization.user_code_entropy` configuration supports 3 values: |
| 81 | + |
| 82 | +- `high`: `user_code` is 8 characters long and consists of alphanumeric characters, excluding some ambiguous symbols |
| 83 | +- `medium`: `user_code` is 8 characters long and consists only of upper case letter |
| 84 | +- `low`: `user_code` is 9 characters long and consists of numbers |
| 85 | + |
| 86 | +Keep in mind that higher entropy may make it harder for the user to enter the user code. |
| 87 | + |
| 88 | +## Device verification user interface implementation |
| 89 | + |
| 90 | +Here is a sample implementation for a device verification UI : |
| 91 | + |
| 92 | +```js |
| 93 | +import { Configuration, OAuth2Api } from "@ory/client" |
| 94 | +import { Request, Response } from "express" |
| 95 | + |
| 96 | +const ory = new OAuth2Api( |
| 97 | + new Configuration({ |
| 98 | + basePath: `https://${process.env.ORY_PROJECT_SLUG}.projects.oryapis.com`, |
| 99 | + accessToken: process.env.ORY_API_KEY, |
| 100 | + }), |
| 101 | +) |
| 102 | + |
| 103 | +// Please note that this is an example implementation. |
| 104 | +// In a production app, please add proper error handling. |
| 105 | +export async function handleLogin(request: Request, response: Response) { |
| 106 | + const challenge = request.query.device_challenge.toString() |
| 107 | + const userCode = request.query.user_code.toString() |
| 108 | + |
| 109 | + // Show the login form if the form was not submitted. |
| 110 | + if (request.method === "GET") { |
| 111 | + response.render("device", { |
| 112 | + challenge, |
| 113 | + userCode, |
| 114 | + }) |
| 115 | + return |
| 116 | + } |
| 117 | + |
| 118 | + // User was authenticated successfully, |
| 119 | + return await ory |
| 120 | + .acceptUserCodeRequest({ |
| 121 | + deviceChallenge: challenge, |
| 122 | + acceptDeviceUserCodeRequest: { |
| 123 | + user_code: userCode, |
| 124 | + }, |
| 125 | + }) |
| 126 | + .then(({ redirect_to }) => { |
| 127 | + response.redirect(String(redirect_to)) |
| 128 | + }) |
| 129 | +} |
| 130 | +``` |
0 commit comments