Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get back a 'refresh_token' for rails app with omniauth google oauth2?

Months ago I created a rails app that authenticated with google using oauth2 - specifically, the omniauth-google-oauth2 gem. I had all the steps working to create the authentication and store a refresh token, but recently oauth2 stopped sending back a 'refresh_token' as part of the response. Originally I was receiving a response that contained:

credentials: {
  refresh_token: XXX,
  token: YYY,
  expires_at: 1374840767,
  expires: true
},

Now I only get back the token that expires within an hour:

credentials: {
  token: YYY,
  expires_at: 1374840767,
  expires: true
},

I really don't know what I did on the application side to change this, so I'm not sure if something changed with google, or if it was something I did. For context, my code looks like:

initializers/omniauth.rb:

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :google_oauth2, 'KEY', 'SECRET', {:scope => "userinfo.email,userinfo.profile,analytics.readonly,adsense.readonly"}
end

authentications_controller.rb is where I receive the response:

def create
  auth = request.env["omniauth.auth"] 
  params = request.env["omniauth.params"]
  project = Project.find(params['project_id'])

  Authentication.create(:project_id => project.id, :provider => auth['provider'], :uid => auth['uid'], :access_token => auth['credentials']['refresh_token'])
  flash[:notice] = "Authentication successful."
  redirect_to owner_view_project_path(project)
end

Is it possible something is missing in my initializers/omniauth.rb file? I've tried adding the following to the options hash, but that didn't seem to bring back the refresh token:

:approval_prompt => "force", :access_type => "offline"

Any help would be greatly appreciated! Thanks in advance!

like image 736
Cam Norgate Avatar asked Jul 27 '13 04:07

Cam Norgate


People also ask

How do I retract Google OAuth token?

To revoke tokens by user ID, you must first configure the OAuth 2.0 policy to add the user ID to the access token. By including end user IDs in access tokens, you will then be able to revoke tokens by end user ID.


2 Answers

The prompt: 'consent' is getting you a refresh token. Something like this should work:

Rails.application.config.middleware.use OmniAuth::Builder do
  scopes = [
      # we need the profile scope in order to login
      "https://www.googleapis.com/auth/userinfo.profile",
      # this and other scopes could be added, but match them up with the
      # features you requested in your API Console
      "https://www.googleapis.com/auth/calendar"
    ]

  provider :google_oauth2, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, { scope: scopes.join(" "), access_type: 'offline',  prompt: 'consent'}
end
like image 171
vladCovaliov Avatar answered Nov 04 '22 08:11

vladCovaliov


As I see, it is enough to add

access_type: 'offline'

to your provider's scope.

The trick is as follows in the Google definition: the refresh token is supplied only in the first time that your app get access to the google account.

Deny authorization and regain authorization if you want to see, again, the refresh token beeing sent by google.

See google original definition here: "If your application needs to refresh access tokens when the user is not present at the browser, then use access_type: offline. This will result in your application obtaining a refresh token the first time your application exchanges an authorization code for a user." (https://developers.google.com/identity/protocols/OAuth2WebServer)

like image 42
Vladimir Brasil Avatar answered Nov 04 '22 07:11

Vladimir Brasil