Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OAuth Token Refresh #816

Open
kwayebopp opened this issue Apr 15, 2024 · 0 comments
Open

OAuth Token Refresh #816

kwayebopp opened this issue Apr 15, 2024 · 0 comments

Comments

@kwayebopp
Copy link

kwayebopp commented Apr 15, 2024

There have been some questions and discussion around implementing an OAuth token refresh mechanism. In my project I ended up implementing a concern that allows the user to refresh the OAuth token on demand, but not automatically:

module Oauth::Refreshable
  extend ActiveSupport::Concern

  included do
    define_method :oauth2_client do
      provider = self.class.name.gsub('Account', '').split('::').last.strip
      omniauth_strategy = "OmniAuth::Strategies::#{provider.capitalize}".constantize

      OAuth2::Client.new(ENV["#{provider.upcase}_CLIENT_ID"], ENV["#{provider.upcase}_CLIENT_SECRET"],
                         omniauth_strategy.default_options.dig('client_options').to_h.symbolize_keys)
    end

    define_method :oauth2_access_token do
      OAuth2::AccessToken.new(oauth2_client, data.dig('credentials', 'token'), data['credentials'].except('token'))
    end

    private :oauth2_client
    private :oauth2_access_token
  end

  def refresh_oauth2_access_token
    new_token = oauth2_access_token.refresh!
    token, refresh_token, expires_at = new_token.to_hash.values_at :access_token, :refresh_token, :expires_at
    new_credentials = data['credentials'].merge('token' => token, 'refresh_token' => refresh_token,
                                                'expires_at' => expires_at)
    update(data: data.merge('credentials' => new_credentials))
  end
end

and an example of including it for a Hubspot OAuth integration:

class Oauth::HubspotAccount < ApplicationRecord
  include Oauth::HubspotAccounts::Base
  include Oauth::Refreshable

  # maybe this should be in the concern?
  def credentials
    data.dig('credentials')
  end
end

Using the refresh_oauth2_access_token method, this example happens in Integrations::HubspotInstallation:

class Integrations::HubspotInstallation < ApplicationRecord
  include Integrations::HubspotInstallations::Base

  def credentials
    oauth_hubspot_account.credentials
  end

  def my_integration_request
     if credentials['expires'] && (Time.now >= Time.at(credentials['expires_at']))
       oauth_hubspot_account.refresh_oauth2_access_token
     end
    # make a request to the integration provider with your updated `credentials` object
  end
end

And finally, @gazayas's take on a potentially adding this to the core repo:

If anything, I could see it being implemented with a flag as an option when super scaffolding since we'd be defining methods, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant