doorkeeper-gem / doorkeeper

Doorkeeper is an OAuth 2 provider for Ruby on Rails / Grape.
https://doorkeeper.gitbook.io/guides/
MIT License
5.27k stars 1.06k forks source link

device code draft #1290

Open bpieck opened 4 years ago

bpieck commented 4 years ago

This is not about an issue in doorkeeper. We were requested to implement the Device Authorization Grant draft for oauth: https://tools.ietf.org/html/draft-ietf-oauth-device-flow-15

We currently are in a mode of refactoring. Now I would be interested if you are interested in this flow and would like to see a PR for doorkeeper. If so, we would consider this in our refactoring work. If not - work on our side is less. But of course we'd like to share this work, if anyone is interested in it.

nbulaj commented 4 years ago

Looks interesting, @bpieck ! It would be great to have this in Doorkeeper :heart:

bpieck commented 4 years ago

Ok, thanks, my colleague Dan Shi will propose a PR in near future :)

Blume73 commented 4 years ago

I would love to integrate this feature in my application as well @bpieck :)

bpieck commented 4 years ago

@Blume73: We have already some implementation here: https://github.com/x-ion-de/doorkeeper/tree/draft-ietf-oauth-device-flow-15 Maybe you like to have a look into how to use it and give some feedback?

Dan Shi will post here some documentation about how to use it in near future.

ddanshi commented 4 years ago

@Blume73

here is a brief walkthrough for the flow. Looking forward to your feedback :)

Migrations

Use generator to create all necessary tables:

rails generate doorkeeper:migration

To enable device flow, run:

rails generate doorkeeper:device_code_grant

This generator will modify some existing columns and add some new ones that comply with the device flow.

Configurations

In Doorkeeper configuration initializer, enable the device flow:

grant_flows %w[urn:ietf:params:oauth:grant-type:device_code]

In addition, one can configure the polling interval and format of the use code in initializer.

  # Configurations for device grant flow
  #
  # The polling interval configures how often the client should poll the access token from
  # authorization server. The default value is 5 seconds
  #
  device_code_polling_interval 5

  #
  # The user code can be composed of letters, digits and hyphens.
  # For example: "4d-6w" means a user code format with 4 digits and 6 letters joined by a hyphen.
  # In case you need both digits and letters for the user code and hyphen is not used to separate
  # letters and digits, which mismatches the accepted format, the default "4w-4w" will be applied.
  #
  user_code_format '4w-4w'

Usage

  1. create applications without Confidential on page /oauth/applications.
  2. Send a post to /oauth/authorize_device to obtain an access grant by using the application uid from step 1:
POST /oauth/authorize_device
Content-Type: application/x-www-form-urlencoded
client_id=<applicatio  uid>

the response example is as follows:

"device_code":"54765a4bc22f30e8d867b93b24fc24d4", 
"user_code":"309349", 
"verification_uri":"https://example.com/oauth/device", 
"verification_uri_complete":"https://example.com/oauth/device/309349", 
"interval":5, 
"expired_in":300
  1. start polling token with client id and device code in a time interval given from step 2

    POST /oauth/token
    Content-Type: application/x-www-form-urlencoded
    grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=<device_code>&client_id=<client_id>

    After the device is authroized, response will give an access token back.

  2. use the verification_uri or verification_uri_complete from step 2 to authorize the device

Blume73 commented 4 years ago

Thank you very much for the hard work you have put in so far. I will try to integrate this feature to my project and give you my feedback as soon as possible.

bpieck commented 4 years ago

thanks, take your time, no pressure. It's just great to get some feedback before we open a PR.

nbulaj commented 4 years ago

Hi guys! I don't have much time right now, so I can't fully check it :( I take a quick look at the implementation and it seems good, but need a deeper analyze.

So feel free to discuss and propose a PR, I'll return to it when I will be not so busy :+1: :bowing_man:

bpieck commented 4 years ago

I opened the PR for discussion.

Blume73 commented 4 years ago

@bpieck I'm sending a post to /oauth/authorize_device. After that, I'm receiving a response like you showed as an example. With the device_code and the client_id I start polling the token. But I'm not receiving any access token back. The response of that post is looking similar to the response of point 2.

Using Inosmnia, I make a post request to /oauth/authorize_device with the parameters grant_type, device_code and client_id.

I'm also trying to make a post only with the parameter grant_type. For that I'm receiving an invalid_client error.

I'm doing something wrong or how can I receive the access token?

ddanshi commented 4 years ago

Hi @Blume73 In case you had 'authoization_pending' back by polling the token, you should go step 4 to authorize the device first before you can get a valid token.

Blume73 commented 4 years ago

@ddanshi First I Send a post to /oauth/authorize_device. After receiving the user code, i go to the URL and paste the user code there. Everything is looking fine. But after I send a second post to /oauth/authorize_device I receive the same answer as in the first post. A new user_code and a new device_code.

  1. Request POST /oauth/authorize_device Content-Type: application/x-www-form-urlencoded client_id=0a4dd341999470dfe41408a6bae1cc90f5743751750721

  2. Response "devicecode":"Qp93qzn88tYskgNPR-PlVagLorhBKmh_sa7NKOmYi4", "user_code":"236-783", "verification_uri":"http://localhost:3001/oauth/device", "verification_uri_complete":"http://localhost:3001/oauth/device/236-783", "interval":5, "expired_in":300

  3. User interactio I go to he verification_uri and authorize through code

  4. Request POST /oauth/authorize_device Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:device_code devicecode=Qp93qzn88tYskgNPR-PlVagLorhBKmh_sa7NKOmYi4 client_id=0a4dd341999470dfe41408a6bae1cc90f5743751750721

And now the respond looks like thiks:

  1. Respond "device_code":"wlCDComkjyP-MbOwJar5JEC9UOlKD4yAjRzK9k9-OOM", "user_code":"299-084", "verification_uri":"http://localhost:3001/oauth/device", "verification_uri_complete":"http://localhost:3001/oauth/device/299-084", "interval":5, "expired_in":300
ddanshi commented 4 years ago

@Blume73 This is so far expected. Every POST request with a valid client id will create a new access grant, which means a new device_code and a new user_code. We could of course check the old access grant's validity before creating a new one. In that case we may then have to calculate the real value of expired_in. Not sure whether we would obtain great benefits from that.

Blume73 commented 4 years ago

Thank you @ddanshi.

After the device is authroized, response will give an access token back.

Where i can find the access token, which endpoint i have to poll?

ddanshi commented 4 years ago

ah sorry! I put the wrong endpoint above. For polling it must be /oauth/token instead of /oauth/authorize_device.

POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:device_code&device_code=<device_code>&client_id=<client_id>

I have corrected it :)

Blume73 commented 4 years ago

@ddanshi now everything is working, perfect! :+1:

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

nbulaj commented 4 years ago

I checked the implementation here - https://github.com/x-ion-de/doorkeeper/tree/draft-ietf-oauth-device-flow-15 - and it seems to me that recently merged #1418 could help to extract this grant flow intro an extension

bpieck commented 4 years ago

Hi, thanks for mentioning. But currently with kids at home while doing Homeoffice and having to prepare to move, I think I will not find time to check it. But ok, let me try this weekend to have at least a look into my wip branch, which I did not touch for half a year. And maybe I try to do some modifications. If I get anything working, I will at least push the current state somewhere.

nbulaj commented 4 years ago

Oh, now worries @bpieck , I just posted it FYI. Do (if you're want and interested in that) whenever you have time :) I totally understand you. If you need any help from me - just let me know.

linhdangduy commented 4 years ago

it seems to me that recently merged #1418 could help to extract this grant flow intro an extension

The extend mechanism is great! Quite curious about how to implement device code flow. I will take it a try, too (based on the drafted works)

nbulaj commented 4 years ago

Based on https://github.com/x-ion-de/doorkeeper/commit/c87f7cd73d27efc8b81a703631f352fe4c42179d I see something like this:

Maybe something more, it's hard to say right now.

For those who interested I can create a new repo under doorkeeper-gem organization and add you guys as collaborators. Just give me your thoughts about the name for the new extension :) And then we could continue to work on it there

irminsul commented 4 years ago

We at EXOP have been using an in-house implementation of the device authorization grant based on some ideas discussed here since late 2019 to allow enterprise users to log in to our apps.

Since quite a few people have expressed their interest in this, we have decided to make our work public. Check it out at https://rubygems.org/gems/doorkeeper-device_authorization_grant.

This does not use the grant flow registration mechanism from https://github.com/doorkeeper-gem/doorkeeper/pull/1418 yet, but we will change that once the next version of Doorkeeper is released.

If you are interested, the best place to get started is probably the example app at https://github.com/exop-group/doorkeeper-device-flow-example.

hickford commented 2 years ago

GitLab uses doorkeeper. Device flow would be useful for GitLab support in git-credential-manager https://gitlab.com/gitlab-org/gitlab/-/issues/225215 https://github.com/GitCredentialManager/git-credential-manager/issues/589

hickford commented 2 years ago

@irminsul now that https://github.com/exop-group/doorkeeper-device_authorization_grant/ is version 1.0 can this issue be closed?

irminsul commented 2 years ago

@hickford: Yes, I think this can be closed.