Skip to content

Implement authentication with OAuth2.0 #58

@GCorbel

Description

@GCorbel

ATM, x-ruby support authentication with OAuth2.0 only with bearer_token. I implemented this to generate bearer token and refresh token so it can be used with the gem :

client_id = # ...
client_secret = # ...
refresh_token = # ...

client = OAuth2::Client.new(
  client_id: client_id,
  client_secret: client_secret,
  token_url: 'https://api.x.com/2/oauth2/token',
  auth_scheme: :basic_auth
)

token = OAuth2::AccessToken.from_hash(client, refresh_token:)
new_token = token.refresh!
new_token.refresh_token # => refresh token have to be saved for later use
bearer_token = new_token.token

client = X::Client.new(
  bearer_token: bearer_token,
  debug_output: Rails.logger,
  default_object_class: HashWithIndifferentAccess
)

ChatGPT propose :

require 'oauth2'

module X
  # OAuth2 authenticator for X API v2
  #
  # This class handles fetching and refreshing OAuth2 tokens,
  # and provides a method to retrieve the Bearer token header for requests.
  class OAuth2Authenticator
    TOKEN_URL = 'https://api.x.com/2/oauth2/token'.freeze

    attr_reader :token, :refresh_token, :expires_at

    # Initializes the authenticator
    # @param client_id [String] your OAuth2 client ID
    # @param client_secret [String] your OAuth2 client secret
    # @param token [String] a valid OAuth2 access token
    # @param refresh_token [String] the OAuth2 refresh token
    def initialize(client_id:, client_secret:, token:, refresh_token:)
      @client_id     = client_id
      @client_secret = client_secret
      @token         = token
      @refresh_token = refresh_token
      @client        = OAuth2::Client.new(
        @client_id,
        @client_secret,
        token_url: TOKEN_URL,
        auth_scheme: :basic_auth
      )
    end

    # Public: Forces a refresh of the access token using the refresh_token.
    # @return [OAuth2::AccessToken] the new token object
    def refresh_token!
      access_token = OAuth2::AccessToken.from_hash(@client, refresh_token: @refresh_token)
      new_token = access_token.refresh!
      @token         = new_token.token
      @refresh_token = new_token.refresh_token
      @expires_at    = new_token.expires_at
      new_token
    end

    # Returns the Authorization header hash to be merged into requests
    # @param request [Object] optional request object (ignored)
    # @return [Hash] headers with Bearer token
    def header(request = nil)
      { 'Authorization' => "Bearer #{@token}" }
    end
  end
end

The authenticator can be used when refresh_token is passed in to X::Client.new, as :

client_id = # ...
client_secret = # ...
refresh_token = # ...

client = X::Client.new(
  client_id:,
  client_secret:,
  refresh_token:
)

refresh_token = client.authenticator.refresh_token!
# Save refresh_token for later use

WDYT ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions