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

Refresh token invalid or expired

ANSWERED

Hi,

I've reviewed every other post on this in the forum, and I'm still lost. I am also new to OAuth2, and programming in general, so that doesn't help either. I have gotten the access token and can perform any action within the initial 60 minute timeframe, but it seems that every attempt to refresh my token fails with the refresh token being invalid or expired. I'm using the same python script everytime, and I only call the function once. Here is my code for the class RefAccessToken is the token refresh:

 

    # Get the access token
    def GetAccessToken(self, access_code):

        # Construct the authentication header
        auth_header = base64.b64encode(self.CLIENT_ID + ':' + self.CLIENT_SECRET)
        headers = {
            'Authorization': 'Basic %s' % auth_header,
            'Content-Type' : 'application/x-www-form-urlencoded'
        }

        # Parameters for requesting tokens (auth + refresh)
        params = {
            'code': access_code,
            'grant_type': 'authorization_code',
            'client_id': self.CLIENT_ID,
            'redirect_uri': self.REDIRECT_URI
        }

        # Place request
        resp = requests.post(self.TOKEN_URL, data=params, headers=headers)
        status_code = resp.status_code
        resp = resp.json()

        if status_code != 200:
            raise Exception("Something went wrong exchanging code for token (%s): %s" % (resp['errors'][0]['errorType'], resp['errors'][0]['message']))

        # Strip the goodies
        token = dict()
        token['access_token']  = resp['access_token']
        token['refresh_token'] = resp['refresh_token']

        return token

    # Get new tokens based if authentication token is expired
    def RefAccessToken(self, token):

        # Construct the authentication header
        auth_header = base64.b64encode(self.CLIENT_ID + ':' + self.CLIENT_SECRET)
        headers = {
            'Authorization': 'Basic %s' % auth_header,
            'Content-Type' : 'application/x-www-form-urlencoded'
        }

        # Set up parameters for refresh request
        params = {
            'grant_type': 'refresh_token',
            'refresh_token': token['refresh_token']
        }

        # Place request
        resp = requests.post(self.TOKEN_URL, data=params, headers=headers)

        status_code = resp.status_code
        resp = resp.json()

        if status_code != 200:
            raise Exception("Something went wrong refreshing (%s): %s" % (resp['errors'][0]['errorType'], resp['errors'][0]['message']))

        # Distil
        token['access_token']  = resp['access_token']
        token['refresh_token'] = resp['refresh_token']

        return token

    # Callback uri generator
    @cherrypy.expose
    def validate(self, code=None):
        if code:
            def query():
# Copy code to webpage for validation yield "Copy this code into the application: " yield cherrypy.request.params.get('code', None) self._shutdown_cherrypy() return query() validate.exposed = True def _shutdown_cherrypy(self): """ Shutdown cherrypy in one second, if it's running """ if cherrypy.engine.state == cherrypy.engine.states.STARTED: threading.Timer(1, cherrypy.engine.exit).start()

and here is the script that calls the refresh:

 

tokenfile = "user_settings.txt"

fit = fitbit.Fitbit()

# Try to read existing token pair
try:
token = json.load(open(tokenfile))
except IOError:
print "No previous token found"
# If not generate a new file
# Get the authorization URL for user to complete in browser.
auth_url = fit.GetAuthorizationUri()
webbrowser.open(auth_url)
cherrypy.quickstart(fit)
# Set the access code that is part of the arguments of the callback URL FitBit redirects to.
access_code = raw_input("Please enter code (from the URL you were redirected to): ")
# Use the temporary access code to obtain a more permanent pair of tokens
token = fit.GetAccessToken(access_code)
# Save the token to a file
json.dump(token, open(tokenfile,'w'))

# Sample API call
response = fit.ApiCall(token, '/1/user/-/profile.json')

# Token is part of the response. Note that the token pair can change when a refresh is necessary.
# So we replace the current token with the response one and save it.
token = response['token']
json.dump(token, open(tokenfile,'w'))

 

Any help you could provide would be greatly appreciated. I'm really at a loss here. Thank you in advance. 

Best Answer
0 Votes
1 BEST ANSWER

Accepted Solutions

I found the issue. It seems that the refresh request is being correctly made, but not updating the information in the file I use for access token and refresh token storage. So on subsequent runs, it attempts to use the expired tokens.

View best answer in original post

Best Answer
0 Votes
7 REPLIES 7

Can you please capture the HTTP request and response? This is easier to debug than your code. You can use a tool like Runscope Traffic Inspector.

Best Answer
0 Votes

Since I don't have runscope could I send a pcap from wireshark? If so where can I send the pcap?

 

Here is the current link: https://app.box.com/s/6vrsk9zrujqrn4qv3h3i0hx8e4i8yq4l

Best Answer
0 Votes

I found the issue. It seems that the refresh request is being correctly made, but not updating the information in the file I use for access token and refresh token storage. So on subsequent runs, it attempts to use the expired tokens.

Best Answer
0 Votes

Hello, 

I have the same issue and quite the same code. Everything is working fine within the 8 hours but after I've got 

Exception: Something went wrong refreshing (invalid_grant): Refresh token invalid.
When I'm executing within the 8 hours timeframe, my access-token and refresh token is updated and changes in my file, after that, invalid grant ...

 

# Set up parameters for refresh request
params = {
'grant_type': 'refresh_token',
'refresh_token': token['refresh_token'],
'expires_in': 31536000
}


What am I missing to create a refresh token expires_in : 1 year instead of 8 hours 28800 sec ?

Best Answer
0 Votes

Hi @valar

 

Most cases, the cause of the error is you're trying to use a refresh token twice.

 

When using the authorization code grant flow, the access token will only last 8 hours.  You do not set an expiration date on the refresh token.  The refresh token should not expire until it is used, and the refresh token can only be used once.  Once you use the refresh token to obtain a new access token & refresh token, you'll need to throw away the old refresh token and replace it with the new refresh token.

 

If you want the access token to last for 1 year, check out the Implicit Grant Flow.  FYI...The Implicit Grant Flow is recommended for public client applications that typically are implemented in a browser.  

 

Gordon

 

 

Gordon Crenshaw
Senior Technical Solutions Consultant
Fitbit Partner Engineering & Web API Support | Google
Best Answer
0 Votes

Thanks you Gordon.

I'm missing something here.

I'm manually getting the authorization code thanks to the callback of the URL type with GetAuthorizationUri():

https://www.fitbit.com/oauth2/authorize?client_id=XXXXX&response_type=code&scope=activity+heartrate+....
I'm using the access code in response to get a access and a refresh token with GetAccessToken(). After 8 hours, I get an 

Exception: Something went wrong refreshing (invalid_grant): Refresh token invalid: 1a322...

Basically, my access-code is not usable anymore and my refresh token, which has never been used, is invalid.

 

I wonder if I'm not doing correctly the first GetAuthorizationUri() ?

Best Answer
0 Votes

Hi @valar,

 

Would you be able to share the code sample that goes through the steps of setting the authorization URL, getting the access & refresh token and requesting the new access token/refresh token once the access token expires?

 

Also, what programming language and OAuth2 Library are you using?

 

If you feel more comfortable private messaging me this information, feel free to do so.

 

Thanks!

Gordon

Gordon Crenshaw
Senior Technical Solutions Consultant
Fitbit Partner Engineering & Web API Support | Google
Best Answer
0 Votes