Reputation: 25
I'm using the google-api-client gem in my Rails project. I have omniauth and devise working, and I have users authenticate through Google.
I thought I had this going very well, until recently. I've noticed my app will throw an error when it fetches the Google Calendar API after one hour. The expiration is one hour from authentication time, and from then I get this error:
Signet::AuthorizationError (Authorization failed. Server message:
{
"error" : "invalid_grant",
"error_description" : "Token has been revoked."
}):
This is separate from invalid refresh tokens, as I do have the refresh token stored in the database. It is sending the refresh token request, which spurs that error above, with this code:
client = Google::APIClient.new(
:application_name => APP_NAME,
:application_version => APP_VERSION,
)
client.authorization.client_id = CLIENT_ID
client.authorization.client_secret = CLIENT_SECRET
client.authorization.refresh_token = user.auth_refresh_token
token_result = client.authorization.fetch_access_token!
I have been very careful as to not sign in and out of my Google accounts, so I cannot figure out why Google would send back this message. If I refresh the page after 55 minutes, all is okay. If I refresh the page after 1 hour, it complains about the access token being revoked.
Has anyone had this issue before? If so, what did you do to fix it? Was it something you had to change in Google's Developer Console?
Upvotes: 0
Views: 967
Reputation: 25
I ended up figuring out the issue, so I thought I'd share what fixed it.
In config/initializers/devise.rb, I have:
scope: 'userinfo.profile, userinfo.email, calendar, https://www.googleapis.com/auth/gmail.readonly', prompt: 'select_account consent' }
What did it for me was the prompt: 'select_account consent'
part. Asking the user for consent at each login seems to keep the refresh token up to date. When the user logs in via Google I check if there was a refresh token in the response, and if there was I save that to the database. If not, I keep their current refresh token in the database.
In all honesty, I really don't get why it was necessary for me to do this but for other users who've shared their code examples it was fine. Perhaps there was a change in the Google's OAuth2 or maybe there's a discrepancy in my method of handling the authorization.
Upvotes: 1