I originally posted this on StackOverflow (I'd appreciate an answer there if you can): http://stackoverflow.com/questions/12784816/youtube-api-refresh-token-revoked-with-400-code-invalid-grant-for-seemingly-n
I've built a server-side PHP application that involves reading/making changes to one users's YouTube account (changes to caption files). The user is authenticated with OAuth 2. I have been storing the refresh_token and making refresh requests successfully when the access_token expires.
But now, I seem to be getting an error, which coincidentally correlates with two things:
I don't know if that means anything.
The error happens when trying to refresh the access token and I'm using the same way of refreshing the token as I have previously. Here are the details:
Error message:
[status code] 400
[reason phrase] Bad Request
[url] https://accounts.google.com/o/oauth2/token
[request] POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
User-Agent: Guzzle/2.8.6 curl/7.24.0 PHP/5.3.10
Content-Type: application/x-www-form-urlencoded
client_id=442147492209.apps.googleusercontent.com&client_secret=D7eLQ5b0Mo1Y8uZ30ReWYwls&grant_type=refresh_token&refresh_token=1%2FCLvAt8V_d9sZznpg5YZdJlOJ58ufbHKL4F5Lw8PiJOg
[response] HTTP/1.1 400 Bad Request
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Date: Tue, 02 Oct 2012 16:28:24 GMT
Content-Type: application/json
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
Transfer-Encoding: chunked
{
"error" : "invalid_grant"
}
If you feel like looking at the source code, it's on github. Here's the relevant line number where refresh takes place: https://github.com/wellcaffeinated/yt-subtitle-explorer/blob/master/app/YTSE/OAuth/LoginManager.php#L330
(You'll notice that I've added a check for this error and ask the administrator to reauthorize the application... but this is far from ideal)
Other posts I've looked into were telling people to use approval_prompt=force... so I am doing that.
My newest suspicion is that since I am requesting offline access (approval_prompt=force) every time the administrator logs in, I keep generating new refresh_tokens (which I don't record unless no others are available). Does google's OAuth have a maximum number of "active" refresh_tokens per application? Or something like that?
Thanks!
I don't know of any reason why you should be seeing errors on a periodic basis. However requiring new refresh token on every login will cause older refresh tokens to expire after a threshold has been reached. Ideally you should only use prompt=force when you have to recover from rare events such as loss of refresh token.
--
{
"issued_to": "820660xxxxxx.apps.googleusercontent.com",
"audience": "820660xxxxxx.apps.googleusercontent.com",
"scope": "http://spreadsheets.google.com/feeds/ https://docs.google.com/feeds/ https://www.googleapis.com/auth/drive.file https://spreadsheets.google.com/feeds/",
"expires_in": 3167,
"access_type": "offline"
}
By the way in the docs are no consistent descriptions how excact to handle the refresh.
In the chapter [1] "Installed Apps" is no hint for check for 4xx errors in opposite
to chapter [2] "Devices". I suppose there is possibly a lack in the implementation after
a token is expired. How long will a refresh token last to generate a new access token?
That's completely unclear and maybe a security issue...
[1] https://developers.google.com/accounts/docs/OAuth2InstalledApp#refresh
[2] https://developers.google.com/accounts/docs/OAuth2ForDevices#obtainingatoken
--