Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Oauth2.0_token() does not work servers requiring client credentials in the header. #288

Closed
tkinsf opened this issue Oct 27, 2015 · 8 comments

Comments

@tkinsf
Copy link

tkinsf commented Oct 27, 2015

httr's oauth2 works fine with google or gibhub. But it does not work with fitbit. Fitbit requires the client crdentials in the "Authorization" header and oauth2.0_token() seems to pass them as parameters rather than in the header. According to oauth2.0 rfc section 2.3.1, supporting the authorization header is a MUST for the server while supporting them as parameters is a MAY. As such, it would be better/safer for client to pass the client id/secret in the header when requesting the access token.

@hadley
Copy link
Member

hadley commented Oct 27, 2015

Please provide a reproducible example. oauth2.0_token() defaults to as_header = TRUE, so I'm pretty sure they're already sent in the header by default.

@tkinsf
Copy link
Author

tkinsf commented Oct 27, 2015

Hadly,

The documentation says that as_header determines weather the oauth is
passed in bearer header or as a parameter. So, I assumed it meant how the
token is passed, not the client credentials in authorization header while
obtaining the token itself. Am I wrong?

I don't have definitive evidence that oauth2.0_token passes client
id/secret as parameters. (I was gonna packet-trace, then I realized that
packets were encoded..). What I know is that fitbit service works fine with
my google script that explicitly passes id/secret in the authorization
header while httr gets "authorization header required" response.

Let me know if you know a way to definitively prove. I'll be happy to
experiment, but my R knowledge is too limited to delve into the library
source code itself..

Thanks
tk
On Oct 27, 2015 12:12 PM, "Hadley Wickham" notifications@github.com wrote:

Please provide a reproducible example. oauth2.0_token() defaults to as_header
= TRUE, so I'm pretty sure they're already sent in the header by default.


Reply to this email directly or view it on GitHub
#288 (comment).

@hadley
Copy link
Member

hadley commented Oct 27, 2015

If you don't want to look at the source, start by providing a reproducible example.

@hadley hadley closed this as completed Dec 17, 2015
@grahamrp
Copy link
Contributor

I also have a problem accessing the fitbit api. I've looked at the https requests in Fiddler and can confirm that the request to obtain the access token by oauth2.0_token does not include the client credentials in the header. Looking at the source, the as_header = TRUE argument to oauth2.0_token does not affect the way the request for the token is made, it only affects subsequent calls to the api once the token has been obtained.

The request for the token is made by init_oauth2.0 via a POST without HTTP Basic authentication and with the client_secret in the body:

# Use authorisation code to get (temporary) access token
  req <- POST(endpoint$access, encode = "form",
    body = list(
      client_id = app$key,
      client_secret = app$secret,
      redirect_uri = redirect_uri,
      grant_type = "authorization_code",
      code = code))

Adding authentication to the POST as below yields a valid token from fitbit.

  # Use authorisation code to get (temporary) access token
  req <- POST(endpoint$access, encode = "form",
              body = list(
                client_id = app$key,
                redirect_uri = redirect_uri,
                grant_type = "authorization_code",
                code = code),
              authenticate(app$key, app$secret))

@hadley
Copy link
Member

hadley commented Dec 31, 2015

@grahamrp that's rather non-standard, but I'd accept a pull request if you wanted to add that as an option.

@danielnjoo
Copy link

Hi all,

Hopefully you'll see this (soon, since reproducible example => API key, which I'll revoke later), but running into problems connecting to FitBit's API. Initially, the app's redirect_uri was giving me issues — FitBit only accepts https connections — but now after successfully authenticating through FitBit, I run into:

"ERROR: [_parse_http_data] invalid HTTP method".

AND Chrome's "This site can't be reached" error. On troubleshooting, I thought it might have to do with security certificates, but Chrome tells me that the certificate is both valid and trusted. So am not quite sure what to do.

Removing the s (in the https) from the redirect_uri that FitBit does complete the authentication process:

"Authentication complete. Please close this page and return to R."

But results in

"Error in oauth2.0_access_token(endpoint, app, code = code, user_params = user_params, : Unauthorized (HTTP 401). Failed to get an access token."

Thanks!

library(httr)
fitbit_endpoint <- oauth_endpoint(
  request = "https://api.fitbit.com/oauth2/token",
  authorize = "https://www.fitbit.com/oauth2/authorize",
  access = "https://api.fitbit.com/oauth2/access_token")
myapp <- oauth_app(
  appname = "Personal Tracking",
  key = "22DG2P",
  secret = "8e04580994aa06264f1996c6f5f75947",
  redirect_uri = "https://localhost:1410/")
scope <- c("sleep","activity")  
fitbit_token <- oauth2.0_token(fitbit_endpoint, myapp,
                               scope = scope, type="code" ,use_basic_auth = TRUE)

@grahamrp
Copy link
Contributor

It's unlikely to be an issue with httr. Try posting over at the fitbit community.

@cristianrohr
Copy link

cristianrohr commented Oct 21, 2019

Hello,
i'm not able to get a token usen using the credentials option with a code,

library(shiny)
library(httr)

# Get key and secret
source("~/.fitbitr")

# Create the app
app <- oauth_app("MicroXploraPortal",
  key = api_keys$key,
  secret = api_keys$secret,
  redirect_uri = "http://localhost:1410/"
)

# Create the endpoint
create_endpoint <- function()
{
  request <- "https://api.fitbit.com/oauth2/token"
  authorize <- "https://www.fitbit.com/oauth2/authorize"
  access <- "https://api.fitbit.com/oauth2/token"
  httr::oauth_endpoint(request, authorize, access)
}
api <- create_endpoint()


# We need to create header, see the following links in details.
# https://community.fitbit.com/t5/Web-API-Development/Invalid-authorization-header-format/td-p/1363901
# https://community.fitbit.com/t5/Web-API-Development/Trouble-with-OAuth-2-0-Tutorial/m-p/1617571#M6583
header <- httr::add_headers(Authorization=paste0("Basic ", RCurl::base64Encode(charToRaw(paste0(api_keys$key, ":", api_keys$secret)))))
content_type <- httr::content_type("application/x-www-form-urlencoded")

# Define the scope
scope <- "profile sleep"

# Get the code
url <- httr::BROWSE(oauth2.0_authorize_url(api, app, scope = scope))

# Manually create a token
token <- httr::oauth2.0_token(
  endpoint = api,
  app = app,
  scope = scope,
  #config_init = c(header, content_type),
  #use_basic_auth = TRUE,
  query_authorize_extra = list(prompt = "login"),
  #type = "code",
  credentials = oauth2.0_access_token(api, app, "COPY PASTED CODE"),
  cache = FALSE
)

I shows me this error:

Error in oauth2.0_access_token(api, app, "MY CODE") :
Unauthorized (HTTP 401). Failed to get an access token.

any idea why is this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants