3

I'm using the Google Analytics API v3. I'll explain the flow of my application now

I used this documentation here: https://developers.google.com/accounts/docs/OAuth2WebServer

First, an OAUTH-URL is generated for the user. The URL looks like this

https://accounts.google.com/o/oauth2/auth?
client_id={CLIENT-ID}&
redirect_uri={REDIRECT-URL}&
state={CUSTOM-NUMBER}&
response_type=code&
access_type=offline&
approval_prompt=force&
scope=https://www.googleapis.com/auth/analytics

When the user clicks on the link he authenticates. Afterwards, with the code, I'm getting the access and refresh token.

I'm sending a request to https://www.googleapis.com/oauth2/v3/token with the parameters

code = Code from Analytics
grant_type = authorization_code
client_secret = CLIENT_SECRET
client_id = CLIENT_ID
redirect_uri = REDIRECT_URI

The cURL options I send are the following:

CURLOPT_HTTPHEADER = array('Content-Type: application/x-www-form-urlencoded')

And of course, the post data is built with http_build_query so I can use that content-type header.

Then, I am getting all profiles of the user, with this URL

https://www.googleapis.com/analytics/v3/management/accounts/~all/webproperties/~all/profiles

This works, and I'm listing all the profiles. The user then selects one of the profiles, and my library gets the current data for the user (pageviews, visits, etc.)

The problem I'm having now, is, that, when I want to refresh the data everyday with a cron, I'm getting the error message:

'error' => 'invalid_grant',
'error_description' => 'Bad Request'

But I have no idea, why?

I saved the access token and the refresh token for the profiles in my database. Then, when reaccessing data before I make requests to access data, I check if the token is valid. But even this fails.

I'm doing this request here

https://accounts.google.com/o/oauth2/tokeninfo?access_token=ya29.BwHqH8NOPVhafk3SnwbqjLZMXub4Q8bemC-8vKVwp-UjRqaIHRXrzEV3WjInhGzl1-phIn7XI4NnDA

It tells me, that the access token is invalid (Which is mysterious, since I just authenticated and 5 seconds later the token isn't valid anymore?

Anyway, then I try to refresh it with this request

URL: https://www.googleapis.com/oauth2/v3/token
Parameters: 

client_secret = CLIENT_SECRET
client_id = CLIENT_ID
refresh_token = REFRESH_TOKEN From my database
grant_type = refresh_token

cURL Options: CURLOPT_HTTPHEADER = array('Content-Type: application/x-www-form-urlencoded')

Then, a post request with the params built with http_build_query

The response looks like this

string(67) "{ "error": "invalid_grant", "error_description": "Bad Request" } "

But I have no idea why. I'm using the access token and refresh token I got 5 minutes earlier and the ones which worked for the first request. Why doesn't it work 5 minutes later with the same tokens? And why can't I even refresh the token?

Musterknabe
  • 5,763
  • 14
  • 61
  • 117

2 Answers2

7

Invalid grant normally has two possible causes.

  1. Your server’s clock is not in sync with NTP. (Solution: check the server time if its incorrect fix it. )
  2. The refresh token limit has been exceeded. (Solution: Nothing you can do they cant have more refresh tokens in use) Applications can request multiple refresh tokens. For example, this is useful in situations where a user wants to install an application on multiple machines. In this case, two refresh tokens are required, one for each installation. When the number of refresh tokens exceeds the limit, older tokens become invalid. If the application attempts to use an invalidated refresh token, an invalid_grant error response is returned. The limit for each unique pair of OAuth 2.0 client and is 25 refresh tokens (note that this limit is subject to change). If the application continues to request refresh tokens for the same Client/Account pair, once the 26th token is issued, the 1st refresh token that was previously issued will become invalid. The 27th requested refresh token would invalidate the 2nd previously issued token and so on.

You should only be storing the Refresh token. The Access token will expire after an hour. Here is a walk though on the different calls Google 3 legged Oauth2 flow.

I wasn't able to figure out anything from your code it looked a little confusing. But I couldn't see anything that really looked wrong that's why I am guessing it might be one of the first two issues.

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
  • Hi, thanks for the answer. To 1. The current date is `Mon Jan 26 11:31:12 CET 2015` This sounds pretty correct to me. 2. The problem is, I'm not even generating a new refresh token. I want to refresh the access token and even the access token doesn't work. Also, I'm using an access token that has be issued 5 minutes before. Meaning, it should still work, shouldn't it? Also, as I said, when the access token is invalid I'm trying to generate a new one with the refresh token. However, I'm not refreshing the refresh token. Just the access token. – Musterknabe Jan 26 '15 at 10:33
  • Is there anything I can change in my code, or can I provide further code to help you understand it? – Musterknabe Jan 26 '15 at 10:33
  • when requesting a new access token you use the refresh token it gives you a new access token your refresh token will never change unless you request access from the user again. – Linda Lawton - DaImTo Jan 26 '15 at 10:34
  • Hi. I think there might be a little misunderstanding here. Yes, the refresh token never changes, I know that. I was just refering to point 2 of your answer, where you say that Google can only issue 25 refresh tokens. However, I'm not even using new refresh tokens. I'm using the current refresh token for all other requests. Which should also generate me a new access token. However, even this fails, with the error in the headline – Musterknabe Jan 26 '15 at 10:36
  • Hi. Just a follow up. It seems like you were right with your point no. 2. The problem was, that I thought, that the refresh tokens are per Google Analytics Profile. So, like UA-XXXXX-01 and UA-XXXXX-02 could have both 25 refresh tokens. But the truth is, that, the refresh tokens count for both of the Accounts. There was just a misunderstanding by me. Google said, that, refresh tokens are per Google User Account and I thought they are per Profile. Thanks for answering. I will now accept your answer and upvote it. :) – Musterknabe Jan 26 '15 at 12:23
  • you are not the only one to confuse this. Glad you got it working. Refresh token is basically your access to a users account. Once you have it you have access to all of there Google analytics stuff. – Linda Lawton - DaImTo Jan 26 '15 at 12:24
6

I know this question is outdated, but I've had this issue because of a slash (/) the code sometimes has and not decoding it properly while extracting from the redirect url.

So token like 4/BGrvsJeuc5BoRRN ... went on my server like 4%2FBGrvsJeuc5BoRRN ....

Posting this in case somebody else will be as dumb as I did.

desertkun
  • 1,027
  • 10
  • 19