httr icon indicating copy to clipboard operation
httr copied to clipboard

OAuth 2.0 resource owner authentication

Open hongooi73 opened this issue 7 years ago • 7 comments

(As opposed to http basic authentication, which is what authenticate does.)

Does httr support this? This is authenticating via a username and password, as opposed to a client secret:

https://tools.ietf.org/html/rfc6749#section-4.3.2

4.3.2.  Access Token Request

   The client makes a request to the token endpoint by adding the
   following parameters using the "application/x-www-form-urlencoded"
   format per Appendix B with a character encoding of UTF-8 in the HTTP
   request entity-body:

   grant_type
         REQUIRED.  Value MUST be set to "password".

   username
         REQUIRED.  The resource owner username.

   password
         REQUIRED.  The resource owner password.

   scope
         OPTIONAL.  The scope of the access request as described by
         Section 3.3.

   If the client type is confidential or the client was issued client
   credentials (or assigned other authentication requirements), the
   client MUST authenticate with the authorization server as described
   in Section 3.2.1.

   For example, the client makes the following HTTP request using
   transport-layer security (with extra line breaks for display purposes
   only):

     POST /token HTTP/1.1
     Host: server.example.com
     Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
     Content-Type: application/x-www-form-urlencoded

     grant_type=password&username=johndoe&password=A3ddj3w

hongooi73 avatar Jan 10 '19 02:01 hongooi73

There is a use_basic_auth argument in oauth2_* function. This passes the key and secret from the app as basic authentication. Did you try ?

What you linked to is specific to Resource Owner Password Credentials Grant and may need a grand_type=password to work. So, I am not sure there is already a full integration with that but is possible by also using user_params= to customize the request.

Do you have an API in mind so that this could be tested further ? it would help to have an example of such an api. thanks!

cderv avatar Jan 10 '19 06:01 cderv

There is a use_basic_auth argument in oauth2_* function. This passes the key and secret from the app as basic authentication. Did you try ?

Yes, the use_basic_auth arg refers to http basic authentication via authenticate().

hongooi73 avatar Jan 10 '19 08:01 hongooi73

Ok, so if you tried, with which API ? I can't help if you can't provide something to test with. I don't have this kind of API at hand. Thank you.

cderv avatar Jan 10 '19 18:01 cderv

By the cunning stratagem of reading the source, I have determined that httr does not support this.

hongooi73 avatar Jan 10 '19 18:01 hongooi73

So this is a feature request.

I really thing that already all the tools are there to make it work, and there is not so much to do to support this grant.

I built a dummy example using httpbin to see the POST request that is sent to the server. I believe only the grant_type is wrong here (because overridden) when using existing tool.

url <- "https://httpbin.org/post"
library(httr)

api_endpoint <- oauth_endpoint(
  authorize = NULL,
  access = "https://httpbin.org/post" # for demo
)

api_app <- oauth_app(
  appname = "app_dummy",
  key = "clientid",
  secret = "clientsecret"
)


json_res <- oauth2.0_access_token(
  endpoint = api_endpoint,
  app = api_app, 
  user_params = list(grant_type = "password", username = "username", password = "password"),
  code = NULL,
  use_basic_auth = TRUE,
  type = "text"
)
#> No encoding supplied: defaulting to UTF-8.

jsonlite::prettify(json_res)
#> {
#>     "args": {
#> 
#>     },
#>     "data": "",
#>     "files": {
#> 
#>     },
#>     "form": {
#>         "client_id": "clientid",
#>         "grant_type": "authorization_code",
#>         "password": "password",
#>         "redirect_uri": "http://localhost:1410/",
#>         "username": "username"
#>     },
#>     "headers": {
#>         "Accept": "application/json, text/xml, application/xml, */*",
#>         "Accept-Encoding": "gzip, deflate",
#>         "Authorization": "Basic Y2xpZW50aWQ6Y2xpZW50c2VjcmV0",
#>         "Connection": "close",
#>         "Content-Length": "130",
#>         "Content-Type": "application/x-www-form-urlencoded",
#>         "Host": "httpbin.org",
#>         "User-Agent": "libcurl/7.59.0 r-curl/3.2 httr/1.4.0"
#>     },
#>     "json": null,
#>     "origin": "176.183.22.128",
#>     "url": "https://httpbin.org/post"
#> }
#> 

In all case it should work using a POST call that will return you the token in response. The POST request is correct here.

res <- POST(url, 
     body = list(grant_type = "password", username = "username", password = "password"),
     authenticate("clientid", "clientsecret"),
     encode = "form"
     )
jsonlite::prettify(content(res, "text"))
#> No encoding supplied: defaulting to UTF-8.
#> {
#>     "args": {
#> 
#>     },
#>     "data": "",
#>     "files": {
#> 
#>     },
#>     "form": {
#>         "grant_type": "password",
#>         "password": "password",
#>         "username": "username"
#>     },
#>     "headers": {
#>         "Accept": "application/json, text/xml, application/xml, */*",
#>         "Accept-Encoding": "gzip, deflate",
#>         "Authorization": "Basic Y2xpZW50aWQ6Y2xpZW50c2VjcmV0",
#>         "Connection": "close",
#>         "Content-Length": "55",
#>         "Content-Type": "application/x-www-form-urlencoded",
#>         "Host": "httpbin.org",
#>         "User-Agent": "libcurl/7.59.0 r-curl/3.2 httr/1.4.0"
#>     },
#>     "json": null,
#>     "url": "https://httpbin.org/post"
#> }
#> 

So I think this 📦 allows it to work, but not supported in an httr oauth dance flow yet, but could easily be.

However, I don't have example to test to see how an API of this type respond. You can either work on something for a PR or provide enough elements for us to see what could be done. Thank you !

Hope it helps.

cderv avatar Jan 10 '19 22:01 cderv

Anyway, this is now implemented in AzureRMR along with device code auth: https://github.com/cloudyr/AzureRMR/blob/master/R/AzureToken.R

Feel free to steal implementation details for httr/httr2. Caveat: not heavily tested yet.

hongooi73 avatar Jan 11 '19 02:01 hongooi73

From the code you linked to, you used a function to wrap the POST call I showed above and extend the Token class. At the end, as expected, it was not so difficult to extend based on existing tools. I believe this ok for you now. It would be nice to have some PR to add the feature into httr too. At least, there is an example to linked too now. Thanks.

For reference as it is not precise, the example API is Azure which have several auth mechanisms, including resource owner grant type and it has been implemented in cloudyr/AzureRMR#5

cderv avatar Jan 11 '19 07:01 cderv

Implemented in httr2: https://httr2.r-lib.org/reference/req_oauth_password.html

hadley avatar Oct 31 '23 20:10 hadley