mirror of
https://github.com/HoneyryderChuck/httpx.git
synced 2025-10-07 00:05:02 -04:00
the oauth plugin
This commit is contained in:
parent
af38476a14
commit
5655c602c7
@ -22,7 +22,7 @@ module HTTPX
|
||||
|
||||
module OptionsMethods
|
||||
def option_digest(value)
|
||||
raise TypeError, ":digest must be a Digest" unless value.is_a?(Authentication::Digest)
|
||||
raise TypeError, ":digest must be a #{Authentication::Digest}" unless value.is_a?(Authentication::Digest)
|
||||
|
||||
value
|
||||
end
|
||||
|
170
lib/httpx/plugins/oauth.rb
Normal file
170
lib/httpx/plugins/oauth.rb
Normal file
@ -0,0 +1,170 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module HTTPX
|
||||
module Plugins
|
||||
#
|
||||
# https://gitlab.com/os85/httpx/wikis/OAuth
|
||||
#
|
||||
module OAuth
|
||||
class << self
|
||||
def load_dependencies(_klass)
|
||||
require_relative "authentication/basic"
|
||||
end
|
||||
end
|
||||
|
||||
SUPPORTED_GRANT_TYPES = %w[client_credentials refresh_token].freeze
|
||||
SUPPORTED_AUTH_METHODS = %w[client_secret_basic client_secret_post].freeze
|
||||
|
||||
class OAuthSession
|
||||
attr_reader :token_endpoint_auth_method, :grant_type, :client_id, :client_secret, :access_token, :refresh_token, :scope
|
||||
|
||||
def initialize(
|
||||
issuer:,
|
||||
client_id:,
|
||||
client_secret:,
|
||||
access_token: nil,
|
||||
refresh_token: nil,
|
||||
scope: nil,
|
||||
token_endpoint: nil,
|
||||
response_type: nil,
|
||||
grant_type: nil,
|
||||
token_endpoint_auth_method: "client_secret_basic"
|
||||
)
|
||||
@issuer = URI(issuer)
|
||||
@client_id = client_id
|
||||
@client_secret = client_secret
|
||||
@token_endpoint = URI(token_endpoint) if token_endpoint
|
||||
@response_type = response_type
|
||||
@scope = case scope
|
||||
when String
|
||||
scope.split
|
||||
when Array
|
||||
scope
|
||||
end
|
||||
@access_token = access_token
|
||||
@refresh_token = refresh_token
|
||||
@token_endpoint_auth_method = String(token_endpoint_auth_method)
|
||||
@grant_type = grant_type || (@refresh_token ? "refresh_token" : "client_credentials")
|
||||
|
||||
unless SUPPORTED_AUTH_METHODS.include?(@token_endpoint_auth_method)
|
||||
raise Error, "#{@token_endpoint_auth_method} is not a supported auth method"
|
||||
end
|
||||
|
||||
return if SUPPORTED_GRANT_TYPES.include?(@grant_type)
|
||||
|
||||
raise Error, "#{@grant_type} is not a supported grant type"
|
||||
end
|
||||
|
||||
def token_endpoint
|
||||
@token_endpoint || "#{@issuer}/token"
|
||||
end
|
||||
|
||||
def load(http)
|
||||
return unless @token_endpoint && @token_endpoint_auth_method && @grant_type && @scope
|
||||
|
||||
metadata = http.get("#{issuer}/.well-known/oauth-authorization-server").raise_for_status.json
|
||||
|
||||
@token_endpoint = metadata["token_endpoint"]
|
||||
@scope = metadata["scopes_supported"]
|
||||
@grant_type = Array(metadata["grant_types_supported"]).find { |gr| SUPPORTED_GRANT_TYPES.include?(gr) }
|
||||
@token_endpoint_auth_method = Array(metadata["token_endpoint_auth_methods_supported"]).find do |am|
|
||||
SUPPORTED_AUTH_METHODS.include?(am)
|
||||
end
|
||||
end
|
||||
|
||||
def merge(other)
|
||||
obj = dup
|
||||
|
||||
case other
|
||||
when OAuthSession
|
||||
other.instance_variables.each do |ivar|
|
||||
val = other.instance_variable_get(ivar)
|
||||
next unless val
|
||||
|
||||
obj.instance_variable_set(ivar, val)
|
||||
end
|
||||
when Hash
|
||||
other.each do |k, v|
|
||||
obj.instance_variable_set(:"@#{k}", v) if obj.instance_variable_defined?(:"@#{k}")
|
||||
end
|
||||
end
|
||||
obj
|
||||
end
|
||||
end
|
||||
|
||||
module OptionsMethods
|
||||
def option_oauth_session(value)
|
||||
case value
|
||||
when Hash
|
||||
OAuthSession.new(**value)
|
||||
when OAuthSession
|
||||
value
|
||||
else
|
||||
raise TypeError, ":oauth_session must be a #{OAuthSession}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def oauth_authentication(**args)
|
||||
with(oauth_session: OAuthSession.new(**args))
|
||||
end
|
||||
|
||||
def with_access_token
|
||||
oauth_session = @options.oauth_session
|
||||
|
||||
oauth_session.load(self)
|
||||
|
||||
grant_type = oauth_session.grant_type
|
||||
|
||||
headers = {}
|
||||
form_post = { "grant_type" => grant_type, "scope" => Array(oauth_session.scope).join(" ") }.compact
|
||||
|
||||
# auth
|
||||
case oauth_session.token_endpoint_auth_method
|
||||
when "client_secret_basic"
|
||||
headers["authorization"] = Authentication::Basic.new(oauth_session.client_id, oauth_session.client_secret).authenticate
|
||||
when "client_secret_post"
|
||||
form_post["client_id"] = oauth_session.client_id
|
||||
form_post["client_secret"] = oauth_session.client_secret
|
||||
end
|
||||
|
||||
case grant_type
|
||||
when "client_credentials"
|
||||
# do nothing
|
||||
when "refresh_token"
|
||||
form_post["refresh_token"] = oauth_session.refresh_token
|
||||
end
|
||||
|
||||
token_request = build_request("POST", oauth_session.token_endpoint, headers: headers, form: form_post)
|
||||
token_request.headers.delete("authorization") unless oauth_session.token_endpoint_auth_method == "client_secret_basic"
|
||||
|
||||
token_response = request(token_request)
|
||||
token_response.raise_for_status
|
||||
|
||||
payload = token_response.json
|
||||
|
||||
access_token = payload["access_token"]
|
||||
refresh_token = payload["refresh_token"]
|
||||
|
||||
with(oauth_session: oauth_session.merge(access_token: access_token, refresh_token: refresh_token))
|
||||
end
|
||||
|
||||
def build_request(*, _)
|
||||
request = super
|
||||
|
||||
return request if request.headers.key?("authorization")
|
||||
|
||||
oauth_session = @options.oauth_session
|
||||
|
||||
return request unless oauth_session && oauth_session.access_token
|
||||
|
||||
request.headers["authorization"] = "Bearer #{oauth_session.access_token}"
|
||||
|
||||
request
|
||||
end
|
||||
end
|
||||
end
|
||||
register_plugin :oauth, OAuth
|
||||
end
|
||||
end
|
@ -34,6 +34,7 @@ module HTTPX
|
||||
| (:grpc, ?options) -> Plugins::grpcSession
|
||||
| (:response_cache, ?options) -> Plugins::sessionResponseCache
|
||||
| (:circuit_breaker, ?options) -> Plugins::sessionCircuitBreaker
|
||||
| (:oauth, ?options) -> Plugins::sessionOAuth
|
||||
| (Symbol | Module, ?options) { (Class) -> void } -> Session
|
||||
| (Symbol | Module, ?options) -> Session
|
||||
|
||||
|
54
sig/plugins/oauth.rbs
Normal file
54
sig/plugins/oauth.rbs
Normal file
@ -0,0 +1,54 @@
|
||||
module HTTPX
|
||||
module Plugins
|
||||
#
|
||||
# https://gitlab.com/os85/httpx/wikis/OAuth
|
||||
#
|
||||
module OAuth
|
||||
def self.load_dependencies: (singleton(Session) klass) -> void
|
||||
|
||||
type grant_type = "client_credentials" | "refresh_token"
|
||||
|
||||
type token_auth_method = "client_secret_basic" | "client_secret_post"
|
||||
|
||||
SUPPORTED_GRANT_TYPES: ::Array[grant_type]
|
||||
|
||||
SUPPORTED_AUTH_METHODS: ::Array[token_auth_method]
|
||||
|
||||
class OAuthSession
|
||||
attr_reader token_endpoint_auth_method: token_auth_method
|
||||
|
||||
attr_reader grant_type: grant_type
|
||||
|
||||
attr_reader client_id: String
|
||||
|
||||
attr_reader client_secret: String
|
||||
|
||||
attr_reader access_token: String?
|
||||
|
||||
attr_reader refresh_token: String?
|
||||
|
||||
attr_reader scope: Array[String]?
|
||||
|
||||
def initialize: (issuer: uri, client_id: String, client_secret: String, ?access_token: String?, ?refresh_token: String?, ?scope: (Array[String] | String)?, ?token_endpoint: String?, ?response_type: String?, ?grant_type: String?, ?token_endpoint_auth_method: ::String) -> void
|
||||
|
||||
def token_endpoint: () -> String
|
||||
|
||||
def load: (Session http) -> void
|
||||
|
||||
def merge: (instance | Hash[untyped, untyped] other) -> instance
|
||||
end
|
||||
|
||||
interface _AwsSdkOptions
|
||||
def oauth_session: () -> OAuthSession?
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
def oauth_authentication: (**untyped args) -> instance
|
||||
|
||||
def with_access_token: () -> instance
|
||||
end
|
||||
end
|
||||
|
||||
type sessionOAuth = Session & OAuth::InstanceMethods
|
||||
end
|
||||
end
|
@ -14,7 +14,7 @@ module Requests
|
||||
assert opts.oauth_session.grant_type == "client_credentials"
|
||||
assert opts.oauth_session.token_endpoint.to_s == "#{server.origin}/token"
|
||||
assert opts.oauth_session.token_endpoint_auth_method == "client_secret_basic"
|
||||
assert opts.oauth_session.scope == "all"
|
||||
assert opts.oauth_session.scope == %w[all]
|
||||
|
||||
opts = HTTPX.plugin(:oauth).oauth_authentication(
|
||||
issuer: "https://smthelse",
|
||||
|
Loading…
x
Reference in New Issue
Block a user