class Rack::OAuth2::Client

Public Class Methods

new(attributes = {}) click to toggle source
# File lib/rack/oauth2/client.rb, line 8
def initialize(attributes = {})
  (required_attributes + optional_attributes).each do |key|
    self.send :"#{key}=", attributes[key]
  end
  @grant = Grant::ClientCredentials.new
  @authorization_endpoint ||= '/oauth2/authorize'
  @token_endpoint ||= '/oauth2/token'
  attr_missing!
end

Public Instance Methods

access_token!(*args) { |req| ... } click to toggle source
# File lib/rack/oauth2/client.rb, line 71
def access_token!(*args)
  headers, params, http_client, options = authenticated_context_from(*args)
  params[:scope] = Array(options.delete(:scope)).join(' ') if options[:scope].present?
  params.merge! @grant.as_json
  params.merge! options
  handle_response do
    http_client.post(
      absolute_uri_for(token_endpoint),
      Util.compact_hash(params),
      headers
    ) do |req|
      yield req if block_given?
    end
  end
end
authorization_code=(code) click to toggle source
# File lib/rack/oauth2/client.rb, line 28
def authorization_code=(code)
  @grant = Grant::AuthorizationCode.new(
    code: code,
    redirect_uri: self.redirect_uri
  )
end
authorization_uri(params = {}) click to toggle source
# File lib/rack/oauth2/client.rb, line 18
def authorization_uri(params = {})
  params[:redirect_uri] ||= self.redirect_uri
  params[:response_type] ||= :code
  params[:response_type] = Array(params[:response_type]).join(' ')
  params[:scope] = Array(params[:scope]).join(' ')
  Util.redirect_uri absolute_uri_for(authorization_endpoint), :query, params.merge(
    client_id: self.identifier
  )
end
force_token_type!(token_type) click to toggle source
# File lib/rack/oauth2/client.rb, line 67
def force_token_type!(token_type)
  @forced_token_type = token_type.to_s
end
jwt_bearer=(assertion) click to toggle source
# File lib/rack/oauth2/client.rb, line 48
def jwt_bearer=(assertion)
  @grant = Grant::JWTBearer.new(
    assertion: assertion
  )
end
refresh_token=(token) click to toggle source
# File lib/rack/oauth2/client.rb, line 42
def refresh_token=(token)
  @grant = Grant::RefreshToken.new(
    refresh_token: token
  )
end
resource_owner_credentials=(credentials) click to toggle source
# File lib/rack/oauth2/client.rb, line 35
def resource_owner_credentials=(credentials)
  @grant = Grant::Password.new(
    username: credentials.first,
    password: credentials.last
  )
end
revoke!(*args) { |req| ... } click to toggle source
# File lib/rack/oauth2/client.rb, line 87
def revoke!(*args)
  headers, params, http_client, options = authenticated_context_from(*args)

  params.merge! case
  when access_token = options.delete(:access_token)
    {
      token: access_token,
      token_type_hint: :access_token
    }
  when refresh_token = options.delete(:refresh_token)
    {
      token: refresh_token,
      token_type_hint: :refresh_token
    }
  when @grant.is_a?(Grant::RefreshToken)
    {
      token: @grant.refresh_token,
      token_type_hint: :refresh_token
    }
  when options[:token].blank?
    raise ArgumentError, 'One of "token", "access_token" and "refresh_token" is required'
  end
  params.merge! options

  handle_revocation_response do
    http_client.post(
      absolute_uri_for(revocation_endpoint),
      Util.compact_hash(params),
      headers
    ) do |req|
      yield req if block_given?
    end
  end
end
saml2_bearer=(assertion) click to toggle source
# File lib/rack/oauth2/client.rb, line 54
def saml2_bearer=(assertion)
  @grant = Grant::SAML2Bearer.new(
    assertion: assertion
  )
end
subject_token=(subject_token, subject_token_type = URN::TokenType::JWT) click to toggle source
# File lib/rack/oauth2/client.rb, line 60
def subject_token=(subject_token, subject_token_type = URN::TokenType::JWT)
  @grant = Grant::TokenExchange.new(
    subject_token: subject_token,
    subject_token_type: subject_token_type
  )
end

Private Instance Methods

absolute_uri_for(endpoint) click to toggle source
# File lib/rack/oauth2/client.rb, line 124
def absolute_uri_for(endpoint)
  _endpoint_ = Util.parse_uri endpoint
  _endpoint_.scheme ||= self.scheme || 'https'
  _endpoint_.host ||= self.host
  _endpoint_.port ||= self.port
  raise 'No Host Info' unless _endpoint_.host
  _endpoint_.to_s
end
authenticated_context_from(*args) click to toggle source
# File lib/rack/oauth2/client.rb, line 133
def authenticated_context_from(*args)
  headers, params = {}, {}
  http_client = Rack::OAuth2.http_client

  # NOTE:
  #  Using Array#extract_options! for backward compatibility.
  #  Until v1.0.5, the first argument was 'client_auth_method' in scalar.
  options = args.extract_options!
  client_auth_method = args.first || options.delete(:client_auth_method)&.to_sym || :basic

  case client_auth_method
  when :basic
    cred = Base64.strict_encode64 [
      Util.www_form_url_encode(identifier),
      Util.www_form_url_encode(secret)
    ].join(':')
    headers.merge!(
      'Authorization' => "Basic #{cred}"
    )
  when :basic_without_www_form_urlencode
    cred = ["#{identifier}:#{secret}"].pack('m').tr("\n", '')
    headers.merge!(
      'Authorization' => "Basic #{cred}"
    )
  when :jwt_bearer
    params.merge!(
      client_assertion_type: URN::ClientAssertionType::JWT_BEARER
    )
    # NOTE: optionally auto-generate client_assertion.
    params[:client_assertion] = if options[:client_assertion].present?
      options.delete(:client_assertion)
    else
      require 'json/jwt'
      JSON::JWT.new(
        iss: identifier,
        sub: identifier,
        aud: absolute_uri_for(token_endpoint),
        jti: SecureRandom.hex(16),
        iat: Time.now,
        exp: 3.minutes.from_now
      ).sign(private_key || secret).to_s
    end
  when :saml2_bearer
    params.merge!(
      client_assertion_type: URN::ClientAssertionType::SAML2_BEARER
    )
  when :mtls
    params.merge!(
      client_id: identifier
    )
    http_client.ssl.client_key = private_key
    http_client.ssl.client_cert = certificate
  else
    params.merge!(
      client_id: identifier,
      client_secret: secret
    )
  end

  [headers, params, http_client, options]
end
handle_error_response(response) click to toggle source
# File lib/rack/oauth2/client.rb, line 225
def handle_error_response(response)
  error = response.body.with_indifferent_access
  raise Error.new(response.status, error)
rescue Faraday::ParsingError, NoMethodError
  raise Error.new(response.status, error: 'Unknown', error_description: response.body)
end
handle_response() { || ... } click to toggle source
# File lib/rack/oauth2/client.rb, line 195
def handle_response
  response = yield
  case response.status
  when 200..201
    handle_success_response response
  else
    handle_error_response response
  end
end
handle_revocation_response() { || ... } click to toggle source
# File lib/rack/oauth2/client.rb, line 205
def handle_revocation_response
  response = yield
  case response.status
  when 200..201
    :success
  else
    handle_error_response response
  end
end
handle_success_response(response) click to toggle source
# File lib/rack/oauth2/client.rb, line 215
def handle_success_response(response)
  token_hash = response.body.with_indifferent_access
  case (@forced_token_type || token_hash[:token_type])&.downcase
  when 'bearer'
    AccessToken::Bearer.new(token_hash)
  else
    raise 'Unknown Token Type'
  end
end