Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refresh token using Omniauth-oauth2 in Rails application

I am using omniauth-oauth2 in rails to authenticate to a site which supports oauth2. After doing the oauth dance, the site gives me the following, which I then persist into the database:

  1. Access Token
  2. Expires_AT (ticks)
  3. Refresh token

Is there an omniauth method to refresh the token automatically after it expires or should I write custom code which to do the same?

If custom code is to be written, is a helper the right place to write the logic?

like image 935
ganeshran Avatar asked Feb 11 '14 16:02

ganeshran


People also ask

How do I get a new refresh token OAuth2?

Because OAuth2 access expires after a limited time, an OAuth2 refresh token is used to automatically renew OAuth2 access. Click the tab for the programming language you're using, and follow the instructions to generate an OAuth2 refresh token and set up the configuration file for your client.

How does OAuth2 refresh token work?

The Refresh Token grant type is used by clients to exchange a refresh token for an access token when the access token has expired. This allows clients to continue to have a valid access token without further interaction with the user.


2 Answers

Omniauth doesn't offer this functionality out of the box so i used the previous answer and another SO answer to write the code in my model User.rb

def refresh_token_if_expired   if token_expired?     response    = RestClient.post "#{ENV['DOMAIN']}oauth2/token", :grant_type => 'refresh_token', :refresh_token => self.refresh_token, :client_id => ENV['APP_ID'], :client_secret => ENV['APP_SECRET']      refreshhash = JSON.parse(response.body)      token_will_change!     expiresat_will_change!      self.token     = refreshhash['access_token']     self.expiresat = DateTime.now + refreshhash["expires_in"].to_i.seconds      self.save     puts 'Saved'   end end  def token_expired?   expiry = Time.at(self.expiresat)    return true if expiry < Time.now # expired token, so we should quickly return   token_expires_at = expiry   save if changed?   false # token not expired. :D end 

And before making the API call using the access token, you can call the method like this where current_user is the signed in user.

current_user.refresh_token_if_expired 

Make sure to install the rest-client gem and add the require directive require 'rest-client' in the model file. The ENV['DOMAIN'], ENV['APP_ID'] and ENV['APP_SECRET'] are environment variables that can be set in config/environments/production.rb (or development)

like image 96
ganeshran Avatar answered Oct 08 '22 23:10

ganeshran


In fact, the omniauth-oauth2 gem and its dependency, oauth2, both have some refresh logic built in.

See in https://github.com/intridea/oauth2/blob/master/lib/oauth2/access_token.rb#L80

# Refreshes the current Access Token # # @return [AccessToken] a new AccessToken # @note options should be carried over to the new AccessToken def refresh!(params = {})   fail('A refresh_token is not available') unless refresh_token   params.merge!(:client_id      => @client.id,                 :client_secret  => @client.secret,                 :grant_type     => 'refresh_token',                 :refresh_token  => refresh_token)   new_token = @client.get_token(params)   new_token.options = options   new_token.refresh_token = refresh_token unless new_token.refresh_token   new_token end 

And in https://github.com/intridea/omniauth-oauth2/blob/master/lib/omniauth/strategies/oauth2.rb#L74 :

self.access_token = access_token.refresh! if access_token.expired? 

So you may not be able to do it directly with omniauth-oauth2, but you can certainly do something along the lines of this with oauth2:

client = strategy.client # from your omniauth oauth2 strategy token = OAuth2::AccessToken.from_hash client, record.to_hash # or token = OAuth2::AccessToken.new client, token, {expires_at: 123456789, refresh_token: "123"} token.refresh! 
like image 30
Eero Avatar answered Oct 09 '22 00:10

Eero