invalid_grant trying to get oAuth token from google

Although this is an old question, it seems like many still encounter it - we spent days on end tracking this down ourselves.

In the OAuth2 spec, "invalid_grant" is sort of a catch-all for all errors related to invalid/expired/revoked tokens (auth grant or refresh token).

For us, the problem was two-fold:

  1. User has actively revoked access to our app
    Makes sense, but get this: 12 hours after revocation, Google stops sending the error message in their response: “error_description” : “Token has been revoked.”
    It's rather misleading because you'll assume that the error message is there at all times which is not the case. You can check whether your app still has access at the apps permission page.

  2. User has reset/recovered their Google password
    In December 2015, Google changed their default behaviour so that password resets for non-Google Apps users would automatically revoke all the user's apps refresh tokens. On revocation, the error message follows the same rule as the case before, so you'll only get the "error_description" in the first 12 hours. There doesn't seem to be any way of knowing whether the user manually revoked access (intentful) or it happened because of a password reset (side-effect).

Apart from those, there's a myriad of other potential causes that could trigger the error:

  1. Server clock/time is out of sync
  2. Not authorized for offline access
  3. Throttled by Google
  4. Using expired refresh tokens
  5. User has been inactive for 6 months
  6. Use service worker email instead of client ID
  7. Too many access tokens in short time
  8. Client SDK might be outdated
  9. Incorrect/incomplete refresh token

I've written a short article summarizing each item with some debugging guidance to help find the culprit. Hope it helps.


I ran into this same problem despite specifying the "offline" access_type in my request as per bonkydog's answer. Long story short I found that the solution described here worked for me:

https://groups.google.com/forum/#!topic/google-analytics-data-export-api/4uNaJtquxCs

In essence, when you add an OAuth2 Client in your Google API's console Google will give you a "Client ID" and an "Email address" (assuming you select "webapp" as your client type). And despite Google's misleading naming conventions, they expect you to send the "Email address" as the value of the client_id parameter when you access their OAuth2 API's.

This applies when calling both of these URL's:

  • https://accounts.google.com/o/oauth2/auth
  • https://accounts.google.com/o/oauth2/token

Note that the call to the first URL will succeed if you call it with your "Client ID" instead of your "Email address". However using the code returned from that request will not work when attempting to get a bearer token from the second URL. Instead you will get an 'Error 400' and an "invalid_grant" message.