Skip to content
This repository has been archived by the owner on Nov 5, 2019. It is now read-only.

oauth2client.client.HttpAccessTokenRefreshError: invalid_grant: Bad Request #451

Closed
kkamkou opened this issue Mar 4, 2016 · 14 comments
Closed

Comments

@kkamkou
Copy link

kkamkou commented Mar 4, 2016

It looks like something on my machine and I have no clue where to go from this point. So, the problem is that two(or 3) weeks ago the bigquery started to reject my calls with invalid token response. I've deleted my account, created a new support one and updated to a new oauth2client version. The result is the same.

(!): at localhost it works without problem!

Version: 2.0.1
Tried with p12 and json

...
  File "/home/gitmostwanted/.virtualenvs/gitmostwanted.com/lib/python3.4/site-packages/oauth2client/util.py", line 137, in positional_wrapper
    return wrapped(*args, **kwargs)
  File "/home/gitmostwanted/.virtualenvs/gitmostwanted.com/lib/python3.4/site-packages/googleapiclient/discovery.py", line 203, in build
    cache)
  File "/home/gitmostwanted/.virtualenvs/gitmostwanted.com/lib/python3.4/site-packages/googleapiclient/discovery.py", line 249, in _retrieve_discovery_doc
    resp, content = http.request(actual_url)
  File "/home/gitmostwanted/.virtualenvs/gitmostwanted.com/lib/python3.4/site-packages/oauth2client/client.py", line 598, in new_request
    self._refresh(request_orig)
  File "/home/gitmostwanted/.virtualenvs/gitmostwanted.com/lib/python3.4/site-packages/oauth2client/client.py", line 864, in _refresh
    self._do_refresh_request(http_request)
  File "/home/gitmostwanted/.virtualenvs/gitmostwanted.com/lib/python3.4/site-packages/oauth2client/client.py", line 933, in _do_refresh_request
    raise HttpAccessTokenRefreshError(error_msg, status=resp.status)
oauth2client.client.HttpAccessTokenRefreshError: invalid_grant: Bad Reques

Wow effect (the second picture is created after 3 seconds, the same request/body/headers):
2016-03-04-42009b6

Console: 2016-03-04-288f70a

@dhermes
Copy link
Contributor

dhermes commented Mar 4, 2016

Check that your system clock is accurate

@theacodes
Copy link
Contributor

This is pretty interesting - we just ran into what appears to be the same issue on an app engine application with user credentials.

@kkamkou
Copy link
Author

kkamkou commented Mar 4, 2016

It looks okay

➜  ~ date
Fri Mar  4 19:24:15 CET 2016
➜  ~ cat /etc/timezone 
Europe/Berlin

@dhermes
Copy link
Contributor

dhermes commented Mar 4, 2016

Why don't you try to force a clock update with ntpdate

@elibixby
Copy link
Contributor

elibixby commented Mar 4, 2016

My error is intermittent, and on appengine, so not sure that it is clock related.

@kkamkou
Copy link
Author

kkamkou commented Mar 4, 2016

Thx, dhermes. Amazing support!. It is true, my problem is related to the ntpdate, just installed ntp.

@kkamkou kkamkou closed this as completed Mar 4, 2016
@dhermes
Copy link
Contributor

dhermes commented Mar 4, 2016

Turns out I'm not a wizard magician, just seen it before (#193).

@jonparrott maybe GAE is having clock issues?

@theacodes
Copy link
Contributor

¯_(ツ)_/¯ I don't think the clock issue would affect user credentials refresh requests, plus we may have found (part) of the bug in #452.

@dhermes
Copy link
Contributor

dhermes commented Mar 8, 2016

Ahh good call. Though I can't verify that the payload doesn't have a timestamp in it.

@redraw
Copy link

redraw commented Jun 4, 2016

hello. thanks for the information!! I have already checked my server time and looks fine..
It's being updated with ntp. Server's timezone is Etc/UTC

However, I'm still getting HttpAccessTokenRefreshError. I'm doing server-side operations. The user token is expired, but fails at refresh. The cliend_id and client_secret are taken from my OAuth2 google console account.

What more information could I provide to you?
I'm using django_orm credentials models.
google-api-python-client version 2.0.1

In [54]: http = httplib2.Http()

In [55]: http = credential.authorize(http)

In [56]: print http.request.credentials.token_expiry
2016-06-03 14:54:22.979126

In [57]: print http.request.credentials.token_uri
https://www.googleapis.com/oauth2/v4/token

In [58]: service = build('calendar', 'v3', http=http)

In [59]: service.calendars().get(calendarId='primary').execute()
[2016-06-04 00:41:24,189] INFO googleapiclient.discovery:817 - URL being requested: GET https://www.googleapis.com/calendar/v3/calendars/primary?alt=json
[2016-06-04 00:41:24,268] INFO oauth2client.client:632 - Refreshing due to a 401 (attempt 1/2)
[2016-06-04 00:41:24,271] INFO oauth2client.client:894 - Refreshing access_token
[2016-06-04 00:41:24,320] INFO oauth2client.client:920 - Failed to retrieve access token: {
 "error": "invalid_grant",
 "error_description": "Bad Request"
}

---------------------------------------------------------------------------
HttpAccessTokenRefreshError               Traceback (most recent call last)
<ipython-input-59-f584db17cccc> in <module>()
----> 1 service.calendars().get(calendarId='primary').execute()

/mnt/web/env/local/lib/python2.7/site-packages/oauth2client/util.pyc in positional_wrapper(*args, **kwargs)

    135                 else:  # IGNORE
    136                     pass
--> 137             return wrapped(*args, **kwargs)
    138         return positional_wrapper
    139

/mnt/web/env/local/lib/python2.7/site-packages/googleapiclient/http.pyc in execute(self, http, num_retries)
    753     resp, content = _retry_request(
    754           http, num_retries, 'request', self._sleep, self._rand, str(self.uri),
--> 755           method=str(self.method), body=self.body, headers=self.headers)
    756
    757     for callback in self.response_callbacks:

/mnt/web/env/local/lib/python2.7/site-packages/googleapiclient/http.pyc in _retry_request(http, num_retries, req_type, sleep, rand, uri, method, *args, **kwargs)
     91
     92     try:
---> 93       resp, content = http.request(uri, method, *args, **kwargs)
     94     except ssl.SSLError:
     95       if retry_num == num_retries:

/mnt/web/env/local/lib/python2.7/site-packages/oauth2client/client.pyc in new_request(uri, method, body, headers, redirections, connection_type)
    631                             resp.status, refresh_attempt + 1,
    632                             max_refresh_attempts)
--> 633                 self._refresh(request_orig)
    634                 self.apply(headers)
    635                 if body_stream_position is not None:

/mnt/web/env/local/lib/python2.7/site-packages/oauth2client/client.pyc in _refresh(self, http_request)
    874                     self._updateFromCredential(new_cred)
    875                 else:
--> 876                     self._do_refresh_request(http_request)
    877             finally:
    878                 self.store.release_lock()

/mnt/web/env/local/lib/python2.7/site-packages/oauth2client/client.pyc in _do_refresh_request(self, http_request)
    931             except (TypeError, ValueError):
    932                 pass
--> 933             raise HttpAccessTokenRefreshError(error_msg, status=resp.status)
    934
    935     def _revoke(self, http_request):

HttpAccessTokenRefreshError: invalid_grant: Bad Request

@redraw
Copy link

redraw commented Jun 4, 2016

Ok. After a loong research I guess I found out the problem. In fact, refresh_token was missing from the user credential, but the issue was tricky.

The refresh token is given for the FIRST time when the application asks the user for permissions. The refresh token is given ONLY IF the flow's step 1 includes the parameters approval_prompt="force"

For some reason the user (me) hadn't got refresh_token in user's credentials, so I revoked permissions from the application on My Account -> Security -> Applications, and restarted the OAuth dance again. Now I got refresh_token.

However, here guys says we would need to send prompt=consent. The big confusion about this, is that it isn't documented on google and this doesn't take place on the library but on the google authentication server

@gregakespret
Copy link

Thanks @redraw !

@joshma
Copy link

joshma commented Aug 26, 2016

@redraw we just hit the same issue, and I thought approval_prompt=force was the recommended way to fix this. Adding prompt=consent errors because you can't use both prompt and approval_prompt - can you confirm that your fix was to just use prompt=consent over approval_prompt=force? (This works, I can confirm, but the original approval_prompt=force isn't documented anywhere I could see.)

@redraw
Copy link

redraw commented Aug 26, 2016

That's right, I only kept prompt=consent and did the job. Here's some doc but it is never clear!

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

No branches or pull requests

7 participants