Creating your own Oauth2 server using Laravel— Device Grant flow

Image attribution to https://morioh.com/p/274f0d5cf0ab

Table of contents

  1. Setting up authorization code flow + with PKCE
  2. Creating your own Oauth2 server using Laravel Passport — client credentials flow
  3. Creating your own Oauth2 server using Laravel Passport — Password grant flow
  4. Creating your own Oauth2 server using Laravel Passport — Implicit grant flow
  5. Creating your own Oauth2 server using Laravel — Device Grant flow — You are here

What we will do

Analogy

Device grants are used to authorize devices such as smart TVs, if you’ve ever used YouTube on a smart TV the ‘link with device’ is an example of this flow. This is especially useful for input constrained devices, which enables you to authenticate with your phone/PC instead.

This article provides a full explanation on how this will be implemented.

For this the analogy goes as follows, you have a customer who wants to purchase some goods but virtually. What you do is you call your friend and tell him to generate a code for you. You then send this code to your customer together with a special URL where they can visit and enter the code to verify themselves. In the meantime you will keep asking your friend if the user has verified themselves (polling). Once the customer visits the page and enters the code, the next time you poll you will receive the access token from your friend which you can use to perform other actions.

The steps are:

  1. Call your friend and ask them to generate a code e.g. 1234
  2. Your friend returns the code together with a verification URL that the user will visit and enter the code.
  3. You relay this information to your customer who then proceeds to visit the URL.
  4. The customer enters the code and verifies themselves.
  5. The next time you ask your friend if the customer has verified themselves yet they say that the customer has verified themselves and here is an access token you can use to interact with your friend’s system.

A few of the parameters we will use

device_code - Uniquely identifies a device, this will be bound to the user session and sort of forms a secret between the server and the device
user_code - The code returned to be used for verification
verification_uri - URL that the user can visit to verify themselves
verification_uri_complete - verification url that auto verifies the user
expires_in - The time this code is valid
interval - polling interval

Step 1: Create and endpoint for the authorization in Oauth2-Server app

Since Laravel Passport doesn’t natively support this, we will have to implement this flow on our own, though I will be using some of passports methods to aid us in our implementation.

We will create the endpoint at oauth/device/code as shown below

This endpoint expects the following parameters

{   "client_id": "YOUR_CLIENT_ID",   "scope": "SPECIFY_SCOPE"}

This endpoint will return the following

{
"device_code": "example device code",
"user_code": "1234",
"verification_uri": "http://oauth2-server.test/oauth/device/activate",
"verification_uri_complete": "http://oauth2-server.test/activate?user_code=1234",
"expires_in": 600,
"interval": 3
}

Let use implement the above

NB: I’m using cache as my temporary database, in reality you will be working with DB directly for the flow, but for the sake of demonstration the above will suffice.

Calling the above endpoint should return something like this.

Another important thing to note, the user_code should be something strong e.g. alphanumeric with 8 characters or more to prevent brute force attack.

Step 2: Set up the activate endpoint on OAuth2-Server app

On the device you can display instructions on how to activate, you can also generate a QR code which allows users to verify themselves, whatever choice you’ll use, the end goal is to allow a user to visit a URL and verify themselves.

The controller looks like this

The above will first of all require the user to log in if they haven’t ideally we should show the authorization screen and allow the user to consent to this request.

This is what the user will see if she/he visits that activate page

Once the user enters the correct code the following will be shown

Step 3: Polling to get access token

While we are waiting for the user to enter the activation token, we can poll the backend. Since we are handling this authorization flow, we will create a custom route where the device will request for a token.

I’m planning to create a package for this and you can check it out and contribute here: https://github.com/Ghostscypher/laravel-passport-device-grant

Ideally the token should be requested from the oauth/token route, but since passport doesn’t natively support device_grant flow I will create the following route oauth/device/token as shown below.

The controller for this looks like the one shown below.

Step 4: Testing

2. Poll to see if token has been activated

3. Activate device

4. Re-query the polling endpoint

Conclusion

I’m issuing a personal access token, in reality we would issue public or client token to the device.

I also highly recommend you change the lifetimes of access tokens.

We are done implementing the OAuth2 authorization flows. Please leave a clap and feedback. Thank you for reading.

References

  1. https://auth0.com/docs/get-started/authentication-and-authorization-flow/device-authorization-flow
  2. https://auth0.com/docs/get-started/authentication-and-authorization-flow/call-your-api-using-the-device-authorization-flow
  3. https://github.com/qiutuleng/laravel-passport-phone-verification-code-grant
  4. https://developer.okta.com/docs/guides/device-authorization-grant/main/

--

--

Freelance developer interested in natural simulations, visualization systems, and anything nerdy.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
G

Freelance developer interested in natural simulations, visualization systems, and anything nerdy.