Last active
March 28, 2025 10:16
-
-
Save GregBaugues/276d7c13e9f7a28db010 to your computer and use it in GitHub Desktop.
Google API OAuth 2.0 refresh token (Ruby on Rails)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The OAuth access token provided by the Google API expires in 60 minutes. After expiration, | |
# you must exchange a refresh token for a new access token. Unfortunately, the the Google API | |
# ruby gem does not include a method for refreshing access tokens. | |
# You can read up on how to refresh an access token here: | |
# https://developers.google.com/accounts/docs/OAuth2WebServer#refresh | |
# This Token model implements that process. It's based off of a Token model that can be created | |
# by running: | |
# rails g model Token token:text refresh_token:string expires_at:datetime | |
# This code assumes you Google API CLIENT_ID and CLIENT_SECRET are set as environment variables. | |
# Google only sends the refresh token the first time you authorize your account. | |
# If you didn't save it, go to your Gmail Account Permissions and revoke permissions to your app | |
class Token < ActiveRecord::Base | |
def to_params | |
{ 'refresh_token' => refresh_token, | |
'client_id' => ENV['CLIENT_ID'], | |
'client_secret' => ENV['CLIENT_SECRET'], | |
'grant_type' => 'refresh_token'} | |
end | |
def request_token_from_google | |
url = URI("https://accounts.google.com/o/oauth2/token") | |
Net::HTTP.post_form(url, self.to_params) | |
end | |
def refresh! | |
data = JSON.parse(request_token_from_google.body) | |
update_attributes( | |
token: data['access_token'], | |
expires_at: Time.now + data['expires_in'].to_i.seconds | |
) | |
end | |
def self.access_token | |
#convenience method to retrieve the latest token and refresh if necessary | |
t = Token.last | |
t.refresh! if t.expires_at < Time.now | |
t.token | |
end | |
end | |
Google only sends the refresh token the first time you authorize your account.
Thanks for including this, super helpful.
Thanks!!
Net::HTTP
does not raise exceptions on HTTP failures (it just returns one of like 40 different error classes).
So when Google returns an error, which it occasionally does, response.body
will be something like "{\n \"error\": \"\",\n \"error_description\": \"\"\n}"
.
This is valid JSON, so it will parse and evaluate to update_attributes(access_token: nil, expires_at: Time.now)
. Even if your refresh token is valid.
This is probably not what you want, so use a sane library, like RestClient, which will raise an exception instead:
def request_token_from_google
RestClient.post("https://accounts.google.com/o/oauth2/token", self.to_params)
end
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you both GregBaugues, adellhk. I found this after spending a lot of time reading Google API docs, saved me a lot of time.