OAuth 2.0 - Device flow
Overview
The device flow is designed for devices that either do not have access to a browser or have limited input capabilities. This flow allows users to share specific data with an application while keeping their usernames, passwords, and other information private.
This grant type can eliminate the need for the client to store the user credentials for future use, by exchanging the credentials with a long-lived access token or refresh token.
How to implement the device-flow
Register the client ID at Identify
From the Safewhere Admin application list, you can create an OAuth2.0 application, then open its sub tabs and update the following:
- On its connection tab:
- Client ID: Specifies the unique ID of the application. Client ID is case-sensitive.
- Client secret: Specifies the Client secret of the application. Client secret is case-sensitive.
- Token endpoint authentication method: Specifies the client authentication method to the token endpoint.
- Allowed Callback URIs: Specifies the redirect URL after successful authentication, e.g https://#identifydomain/runtime/oauth2/devicepairingcallback
- Application name: Specifies the name of the application
- Security token audiences: Specifies the recipients (usually in URI format) that issued access tokens are intended for. When the resource parameter is missing, an access token is issued with its 'aud' claim set to all configured audiences.
- On its security tab:
- JWS algorithm: Either RSASigning or HMACSymmetric.
- Symmetric signing key: Used to generate a HMAC Symmetric signing key; key can be 32-byte, 48-byte, or 64-byte. You can then either copy the key and paste it to the configuration or check the appropriate check box and click Select key to apply it.
- Allow device pairing flow: This setting must be True.
- Code life time (minutes): Specifies the input code lifetime. Its default value is 60.
- Number of user code group: Specifies the number of 4-character groups of a code. Its default value is 2.
Here is the screenshot of a sample connection:
Ask for a token
The flow has the following steps:
- The client requests access from the authorization server and includes its client identifier in the request.
- The authorization server issues a verification code and an end-user code, and provides the end-user verification URI.
- The client instructs the end-user to use his or her user-agent elsewhere (mostly a browser on a laptop or a mobile phone) and visit the provided end-user verification URI. The client provides the end-user with the end-user code to enter to grant access.
- The authorization server authenticates the end-user and prompts the end-user to grant the client's access request. If the user has not logged in yet, he or she will need to log in.
- While the end-user authorizes (or denies) the client's request, the client repeatedly polls the authorization server to find out if the end-user has completed the end-user authorization step.
- Assuming the end-user has granted access, the authorization server validates the verification code provided by the client and responds with the access token.
Step 1: Request device and user codes
Perform a POST operation to the device_authorization endpoint:
https://#identifydomain/runtime/oauth2/device_authorization
URI parameters:
Parameter | Description |
---|---|
client_id | Your application's client ID |
client_secret | Optional. Unless you specify the client secret, Identify will validate it with the client secret which is configured in the OAuth2.0 protocol connection |
scope | Optional. A space-delimited list of scopes that identifies the resources that your application could access on the user's behalf |
Step 2: Handle the authorization server response
The authorization server returns a JSON object to your device.
{"device_code":"LRPDM3ETN83M74VVQF4QE3C2TIANIFMBUMIMK9BQ","user_code":"Z3EV-TJ8E","verification_uri":"https://idpmaster60.safewhere.local/runtime/oauth2/devicepairing","verification_uri_complete":"https://idpmaster60.safewhere.local/runtime/oauth2/devicepairing?user_code=Z3EV-TJ8E"}
Its content includes:
- device_code: The device verification code.
- user_code: The device verification code.
- verification_uri: The end-user verification URI on the authorization server
- verification_uri_complete: The end-user verification URI on the authorization server with its user_code_
Step 3: User login and consent
- The user navigates to the OAuth2/devicepairing endpoint which is shown up from the verification_uri paramete or the verification_uri_complete parameter above:
- The user enters the verification code.
- If the code is correct, and if the user has not logged yet, the user will need to log in.
- The user approves consent.
Step 4: Poll the authorization server
While the end-user authorizes (or denies) the client's request, the client repeatedly polls the authorization server via the method POST to the token endpoint
https://#identifydomain/runtime/oauth2/token.idp
URI parameters:
Parameter | Description |
---|---|
client_id | Your application's Client ID. |
grant_type | The value must be "urn:ietf:params:oauth:grant-type:device_code". |
Device_code | The value comes from the message which is received at the 2nd step. |
Step 5: Get the access token
If the user has approved the grant, the token endpoint responds with a success response
{"token_type":"Bearer","access_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IkNVYjM4QjMzMjZ4TkI4RFRVN1JkZjhyWkJYNCIsIng1dCI6IkNVYjM4QjMzMjZ4TkI4RFRVN1JkZjhyWkJYNCIsInR5cCI6IkpXVCJ9.eyJ1aUlkIjoiZTgwODdmMGQtM2JiZi00YWExLTk3MmUtOTc2NGZkMjdjNDgyIiwidW5pcXVlX25hbWUiOiJhZG1pbiIsInN1YiI6ImFkbWluIiwidXJuOmFueWlkOnJvbGUiOiJBZG1pbmlzdHJhdG9yIiwidXJuOmlkZW50aWZ5OnJlc3QtYXBpOnJvbGUiOiJBZG1pbmlzdHJhdG9yIiwicm9sZSI6WyJDbGFpbUFkbWluIiwiQ2xhaW1UcmFuc2Zvcm1hdGlvbkFkbWluIiwiQ29ubmVjdGlvbkFkbWluIiwiR3JvdXBBZG1pbiIsIklkZW50aWZ5IFNlcnZpY2UiLCJPcmdhbml6YXRpb25BZG1pbiIsIlN5c3RlbVNldHVwQWRtaW4iLCJVc2VyQWRtaW4iXSwibmFtZSI6ImFkbWluIiwidXJuOmludGVybmFsOnVzZXJpZCI6ImNhN2I0OGFjLTgzMGYtNDEyNi1iZGMyLTdhYmM3N2JmNDg4YSIsInRva2VuX3VzYWdlIjoiYWNjZXNzX3Rva2VuIiwianRpIjoiZDlkYzExZDctOTYxNS00N2ExLWI3MjEtN2YxNzI0ZGYxM2NmIiwic2NvcGUiOiJpZGVudGlmeSplbXB0eSIsImF1ZCI6Imh0dHBzOi8vaWRwbWFzdGVyNjAuc2FmZXdoZXJlLmxvY2FsL3J1bnRpbWUvIiwiYXpwIjoiY2xpZW50X2RldmljZV9wYWlyaW5nX2lkIiwiaWF0IjoxNTkwMzczMzE1LCJuYmYiOjE1OTAzNzMzMTUsImV4cCI6MTU5MDM3NjkxNSwiaXNzIjoiaHR0cHM6Ly9pZHBtYXN0ZXI2MC5zYWZld2hlcmUubG9jYWwvcnVudGltZS9vYXV0aDIifQ.zgX10RkbJLjUbVSPQushr2Jqp25D5GlSDqkR5U95fFM7ClJOuLszo7gj2Z9LMbPc_pvvk8VqWosV0_cyPHZPGd_ZAqce5KfeSVqOON9Yz5xRJNdTzNljbKw59A4zIdYQoWhtXbrb5DMc6DWAzXIP-MFN2MidV194nZT645w3VeE3mNrNqngFPUm0_PSGfJSYpyUFRUcSxeLbfT2KXwwtUG9jGE169b3omni84aG6AZ6MCIAltbdhHtzOnpJp3Cxg8jyJSGgmasMYhkHKZT_xtGPttJiy88x-_JEHFnaCvcFBXHpejra94qBrojf_z8gs6HRekNTvyvD83VDOErw9Rw","expires_in":3600}
If you decode the access_token, you will see that it contains the following claims:
{
"uiId": "e8087f0d-3bbf-4aa1-972e-9764fd27c482",
"unique_name": "admin",
"sub": "admin",
"urn:anyid:role": "Administrator",
"urn:identify:rest-api:role": "Administrator",
"role": [
"ClaimAdmin",
"ClaimTransformationAdmin",
"ConnectionAdmin",
"GroupAdmin",
"Identify Service",
"OrganizationAdmin",
"SystemSetupAdmin",
"UserAdmin"
],
"name": "admin",
"urn:internal:userid": "ca7b48ac-830f-4126-bdc2-7abc77bf488a",
"token_usage": "access_token",
"jti": "d9dc11d7-9615-47a1-b721-7f1724df13cf",
"scope": "identify*empty",
"aud": "https://idpmaster60.safewhere.local/runtime/",
"azp": "client_device_pairing_id",
"iat": 1590373315,
"nbf": 1590373315,
"exp": 1590376915,
"iss": "https://idpmaster60.safewhere.local/runtime/oauth2"
}