Cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

invalid_grant immediately after revoking & regranting access

ANSWERED

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.

Best Answer
0 Votes
2 BEST ANSWERS

Accepted Solutions

@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?

View best answer in original post

Best Answer
0 Votes

[SCREAM]

 

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.

View best answer in original post

Best Answer
0 Votes
9 REPLIES 9

@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?

Best Answer
0 Votes

response_type = token

Best Answer
0 Votes

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.

Best Answer
0 Votes

Cool, glad that fixes it!

Best Answer
0 Votes

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?!?

Best Answer
0 Votes

I would take a look at the response body to the HTTP 400, it should give you some idea of whats wrong.

Best Answer
0 Votes

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
)
Best Answer
0 Votes

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?

Best Answer
0 Votes

[SCREAM]

 

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.

Best Answer
0 Votes