So, your Google oAuth tokens keep expiring with grant_type errors? Here’s what you need to do.

If you’re creating a tool that interacts with Google’s web services, you’ll need to do the oAuth dance.

I hate the oAuth dance.

I hate it because there is so little feedback on what you’re doing wrong, so here’s a quick write-up of what I found out you need to do to get it working properly for a permanent authorisation.

You’ve probably been at this for a while when you found this, so without further ado here’s the tl;dr.

If you are sure your code is correct, invalidate the existing oAuth token from your google account!

The oAuth dance for ‘offline’ applications in a nutshell

An ‘offline’ oAuth token allows you to reuse the the refresh_token you receive from the initial request after executing the oauth2/auth request.

If you’re like me, you forgot to add the access_type=offline parameter when you first started fiddling with this, and you’ve been retrying about 20 times, thought you had it working, only to find that the refresh token expires again and again, so you have give the permission from the browser and do the oAuth dance again and again.

Here’s an overview what you need to do to make it work correctly

Step zero

First, make sure that any existing token you have registered for your app is deauthorized via the method described above. 
Google *will* re-issue a new auth code for the same access_type you first requested even if you pass different parameters to this request!

Step one

Make sure that your initial oAuth dance request includes access_type=offline and approval_prompt=force

https://accounts.google.com/o/oauth2/auth?response_type=code&scope={SCOPE}&client_id{CLIENT_ID}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&access_type=offline&approval_prompt=force

Open that in a browser window to get the copy/pasta-able code after you click authorize.

Step 2

Now make an oAuth token request with grant_type=authorization_code

curl “https://accounts.google.com/o/oauth2/token" -d “client_secret={CLIENT_SECRET}&client_id={CLIENT_ID}&code={CODE}&grant_type=authorization_code&redirect_uri=urn:ietf:wg:oauth:2.0:oob”

This will yield a JSON response with information you will need to store and be able to modify:

  • a refresh_token
    You’re going to use this to fetch a new access_token if the current access token expired.
  • an access_token
    You can use this immediately to make authorized requests to the oAuth api. It expires after max_ageis
  • expires_in
    The number of seconds access_token will be valid.
Pro tip: Store a value named max_age (now() + expires_in) to be able to check if you need a new token.

Step 3 (start of normal oAuth flow)

if (now > max_age) {
 curl “https://accounts.google.com/o/oauth2/token" -d “client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&refresh_token={REFRESH_TOKEN}&grant_type=refresh_token”
 // store new access_token
 // store new expires_in
}
Pro Tip: DO NOT fetch a new token on every regular oAuth request you make, google will punish you with vague errors!

Step 4

Live your life again as if you know how to oAuth, execute some API requests, for example

curl \
-H “Authorization: Bearer {ACCESS_TOKEN}” \
-H “x-goog-api-version: 2” \
-H “Content-Type: application/json” \
-X POST \
-d ‘{”target”: ”default”}’ \
 https://www.googleapis.com/chromewebstore/v1.1/items/{APP_ID}/publish

Hope that clears things up. Good luck!

Like what you read? Give SchizoDuckie a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.