Creating your own Oauth2 server using Laravel— Device Grant flow
Table of contents
- Initial config — Recommend you start here
- Setting up authorization code flow + with PKCE
- Creating your own Oauth2 server using Laravel Passport — client credentials flow
- Creating your own Oauth2 server using Laravel Passport — Password grant flow
- Creating your own Oauth2 server using Laravel Passport — Implicit grant flow
- Creating your own Oauth2 server using Laravel — Device Grant flow — You are here
What we will do
- We will implement device grant flow.
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:
- Call your friend and ask them to generate a code e.g. 1234
- Your friend returns the code together with a verification URL that the user will visit and enter the code.
- You relay this information to your customer who then proceeds to visit the URL.
- The customer enters the code and verifies themselves.
- 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
- Send a request to generate device code
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
- https://github.com/Ghostscypher/OAuth2-Tutorial — Github repo for this tutorial
- https://auth0.com/docs/get-started/authentication-and-authorization-flow/device-authorization-flow
- https://auth0.com/docs/get-started/authentication-and-authorization-flow/call-your-api-using-the-device-authorization-flow
- https://github.com/qiutuleng/laravel-passport-phone-verification-code-grant
- https://developer.okta.com/docs/guides/device-authorization-grant/main/