11-10-2015 12:10 - edited 11-10-2015 12:11
11-10-2015 12:10 - edited 11-10-2015 12:11
I keep making baby steps as I move through this authenticate process. I've successfully received the authorization token & am trying to get an access/refresh token at /oauth2/token.
My process was this so far:
Client has just clicked a link to show them the Fitbit authorize screen, "Allow" is clicked, client is redirected back to my app via the redirect URI. From that, I copy the access_token from the response in the fragment, paste it in my Postman field for "code". Then I click send & get the following:
Postman request:
POST /oauth2/token HTTP/1.1 Host: api.fitbit.com Authorization: Basic Base64Encoded-client_id:client_secret Cache-Control: no-cache Postman-Token: df48ced1-413b-6240-c972-d603feb52aa6 Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&client_id=MyClientId&redirect_uri=http%3A%2F%2Fwww.myurl.com%2Ffitness%2Fauthorize%2F1&code=SuperLongCodeHere
Response:
Headers: access-control-allow-credentials → true access-control-allow-origin → chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop cache-control → no-cache, must-revalidate cf-ray → 24341c3cb14203e2-DFW content-encoding → gzip content-language → en-US content-type → application/json;charset=UTF-8 date → Tue, 10 Nov 2015 19:19:40 GMT expires → Thu, 01 Jan 1970 00:00:00 GMT pragma → no-cache server → cloudflare-nginx status → 400 Bad Request vary → Accept-Encoding version → HTTP/1.1 x-frame-options → SAMEORIGIN x-ua-compatible → IE=edge,chrome=1 BODY: { "errors": [ { "errorType": "invalid_grant", "message": "Authorization code invalid or expired: SuperLongCodeHere Visit https://dev.fitbit.com/docs/oauth2 for more information on the Fitbit Web API authorization process." } ], "success": false }
My redirect_uri is identical to the redirect_uri used to generate the authorization token and what was used on the app settings. I wanted to get Postman working before I got my app sending requests.
Answered! Go to the Best Answer.
11-10-2015 12:27
11-10-2015 12:27
@laygo wrote:
From that, I copy the access_token from the response in the fragment, paste it in my Postman field for "code".
It sounds like from that you might be using the Implicit Grant flow. Are you sending response_type=code or token to the /oauth2/authorize page?
11-11-2015 12:48
11-11-2015 12:48
ARGH! So, I figured it out. Since I was changing servers & they were using different config files, the config for my redirect_uri was different . . . BY A SINGLE TRAILING SLASH. UGH! I wish the error message was a lil more detailed. I get it was indeed a bad request, but it had to fail some where in the code & just a LIL more text to accompany the error message would've been nice. 😉
Thanks.
11-10-2015 12:27
11-10-2015 12:27
@laygo wrote:
From that, I copy the access_token from the response in the fragment, paste it in my Postman field for "code".
It sounds like from that you might be using the Implicit Grant flow. Are you sending response_type=code or token to the /oauth2/authorize page?
11-10-2015 12:29
11-10-2015 12:29
response_type = token
11-10-2015 12:35 - edited 11-10-2015 12:36
11-10-2015 12:35 - edited 11-10-2015 12:36
UGH! I keep getting crossed up with Implicit/Authorization flows. I was confused when I read the Implicit just providing the access_token, but no refresh token (re-requesting authorization wouldn't be prudent for our application), so I THOUGHT I switched it around, but um, guess not?
Thanks for the insight.
11-10-2015 13:00
11-10-2015 13:00
Cool, glad that fixes it!
11-10-2015 15:16 - edited 11-10-2015 15:21
11-10-2015 15:16 - edited 11-10-2015 15:21
Ok, I'm thoroughly lost, this is a simple request, but something is amiss. The request from Postman is posted above & it works now if I take the code response & paste it, but in my code, this request fails! It looks nearly the same! ARGH!
This is the exception:
Client error response [status code] 400 [reason phrase] Bad Request [url] https://api.fitbit.com/oauth2/token
The programatically built request with all the values validated!
Guzzle\Http\Message\Header\HeaderCollection Object ( [headers:protected] => Array ( [host] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => api.fitbit.com ) [header:protected] => Host [glue:protected] => , ) [authorization] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => Basic Base64Encode(client_id:client_secret) ) [header:protected] => Authorization [glue:protected] => , ) [content-type] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => application/x-www-form-urlencoded; charset=utf-8 ) [header:protected] => Content-Type [glue:protected] => , ) [user-agent] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => Guzzle/3.9.3 curl/7.19.7 PHP/5.5.30 ) [header:protected] => User-Agent [glue:protected] => , ) ) ) Guzzle\Http\QueryString Object ( [fieldSeparator:protected] => & [valueSeparator:protected] => = [urlEncode:protected] => RFC 3986 [aggregator:protected] => [data:protected] => Array ( [code] => CodeResponseFromFitbit/oauth2/authorize [client_id] => MyClientId [redirect_uri] => http://www.url.omg/fitness/authorize/1/ [grant_type] => authorization_code ) )
What am I missing?!?
11-10-2015 15:20
11-10-2015 15:20
I would take a look at the response body to the HTTP 400, it should give you some idea of whats wrong.
11-10-2015 15:26 - edited 11-10-2015 15:31
11-10-2015 15:26 - edited 11-10-2015 15:31
Seeing if I can get more/other info, but here's first pass (it's my 1st time working w/Guzzle):
UPDATED RESPONSE:
Guzzle\Http\Message\Response Object ( [body:protected] => Guzzle\Http\EntityBody Object ( [contentEncoding:protected] => [rewindFunction:protected] => [stream:protected] => Resource id #146 [size:protected] => [cache:protected] => Array ( [wrapper_type] => PHP [stream_type] => TEMP [mode] => w+b [unread_bytes] => 0 [seekable] => 1 [uri] => php://temp [is_local] => 1 [is_readable] => 1 [is_writable] => 1 ) [customData:protected] => Array ( ) ) [reasonPhrase:protected] => Bad Request [statusCode:protected] => 400 [info:protected] => Array ( [url] => https://api.fitbit.com/oauth2/token [content_type] => application/json;charset=UTF-8 [http_code] => 400 [header_size] => 725 [request_size] => 424 [filetime] => -1 [ssl_verify_result] => 0 [redirect_count] => 0 [total_time] => 0.181469 [namelookup_time] => 0.086082 [connect_time] => 0.094333 [pretransfer_time] => 0.128175 [size_upload] => 162 [size_download] => 257 [speed_download] => 1416 [speed_upload] => 892 [download_content_length] => -1 [upload_content_length] => 0 [starttransfer_time] => 0.155091 [redirect_time] => 0 [redirect_url] => [primary_ip] => 104.16.45.187 [certinfo] => Array ( ) ) [effectiveUrl:protected] => https://api.fitbit.com/oauth2/token [headers:protected] => Guzzle\Http\Message\Header\HeaderCollection Object ( [headers:protected] => Array ( [server] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => cloudflare-nginx ) [header:protected] => Server [glue:protected] => , ) [date] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => Tue, 10 Nov 2015 23:28:37 GMT ) [header:protected] => Date [glue:protected] => , ) [content-type] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => application/json;charset=UTF-8 ) [header:protected] => Content-Type [glue:protected] => , ) [transfer-encoding] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => chunked ) [header:protected] => Transfer-Encoding [glue:protected] => , ) [connection] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => keep-alive ) [header:protected] => Connection [glue:protected] => , ) [set-cookie] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => __cfduid=dca97d3b2220b15f9036d1070627ab8cb1447198117; expires=Wed, 09-Nov-16 23:28:37 GMT; path=/; domain=.fitbit.com; HttpOnly [1] => JSESSIONID=59B28010E55818A1989E290C46F9ADD7.fitbit1; Path=/; HttpOnly [2] => fhttps=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ ) [header:protected] => Set-Cookie [glue:protected] => , ) [x-ua-compatible] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => IE=edge,chrome=1 ) [header:protected] => X-UA-Compatible [glue:protected] => , ) [expires] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => Thu, 01 Jan 1970 00:00:00 GMT ) [header:protected] => Expires [glue:protected] => , ) [cache-control] => Guzzle\Http\Message\Header\CacheControl Object ( [directives:protected] => [values:protected] => Array ( [0] => no-cache, must-revalidate ) [header:protected] => Cache-control [glue:protected] => , ) [pragma] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => no-cache ) [header:protected] => Pragma [glue:protected] => , ) [content-language] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => en-US ) [header:protected] => Content-Language [glue:protected] => , ) [vary] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => Accept-Encoding ) [header:protected] => Vary [glue:protected] => , ) [x-frame-options] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => SAMEORIGIN ) [header:protected] => X-Frame-Options [glue:protected] => , ) [cf-ray] => Guzzle\Http\Message\Header Object ( [values:protected] => Array ( [0] => 243588e7f95e1fe8-DFW ) [header:protected] => CF-RAY [glue:protected] => , ) ) ) [headerFactory:protected] => Guzzle\Http\Message\Header\HeaderFactory Object ( [mapping:protected] => Array ( [cache-control] => Guzzle\Http\Message\Header\CacheControl [link] => Guzzle\Http\Message\Header\Link ) ) [params:protected] => Guzzle\Common\Collection Object ( [data:protected] => Array ( ) ) [protocol:protected] => HTTP [protocolVersion:protected] => 1.1 )
11-11-2015 08:01
11-11-2015 08:01
I don't know if this helps, but the redirect calls our web server: www.server.com, but the /oauth2/token call is made from our API server: api.server.com
Would that have any bearing?
11-11-2015 12:48
11-11-2015 12:48
ARGH! So, I figured it out. Since I was changing servers & they were using different config files, the config for my redirect_uri was different . . . BY A SINGLE TRAILING SLASH. UGH! I wish the error message was a lil more detailed. I get it was indeed a bad request, but it had to fail some where in the code & just a LIL more text to accompany the error message would've been nice. 😉
Thanks.