class HTTPX::Plugins::OAuth::OAuthSession

  1. lib/httpx/plugins/oauth.rb
Superclass: Object

Implements the bulk of functionality and maintains the state associated with the management of the the lifecycle of an OAuth session.

Public Class methods

new( issuer:, client_id:, client_secret:, access_token: nil, refresh_token: nil, scope: nil, audience: nil, token_endpoint: nil, grant_type: nil, token_endpoint_auth_method: nil )
[show source]
   # File lib/httpx/plugins/oauth.rb
37 def initialize(
38   issuer:,
39   client_id:,
40   client_secret:,
41   access_token: nil,
42   refresh_token: nil,
43   scope: nil,
44   audience: nil,
45   token_endpoint: nil,
46   grant_type: nil,
47   token_endpoint_auth_method: nil
48 )
49   @issuer = URI(issuer)
50   @client_id = client_id
51   @client_secret = client_secret
52   @token_endpoint = URI(token_endpoint) if token_endpoint
53   @scope = case scope
54            when String
55              scope.split
56            when Array
57              scope
58   end
59   @audience = audience
60   @access_token = access_token
61   @refresh_token = refresh_token
62   @token_endpoint_auth_method = String(token_endpoint_auth_method) if token_endpoint_auth_method
63   @grant_type = grant_type || (@refresh_token ? "refresh_token" : "client_credentials")
64   @expires_at = nil
65   @token_mon = Monitor.new
66 
67   unless @token_endpoint_auth_method.nil? || SUPPORTED_AUTH_METHODS.include?(@token_endpoint_auth_method)
68     raise Error, "#{@token_endpoint_auth_method} is not a supported auth method"
69   end
70 
71   return if SUPPORTED_GRANT_TYPES.include?(@grant_type)
72 
73   raise Error, "#{@grant_type} is not a supported grant type"
74 end

Public Instance methods

access_token()
[show source]
   # File lib/httpx/plugins/oauth.rb
90 def access_token
91   @token_mon.synchronize do
92     if (expires_at = @expires_at) && expires_at < Time.now.to_i
93       reset!
94     end
95 
96     @access_token
97   end
98 end
expires_at()
[show source]
   # File lib/httpx/plugins/oauth.rb
86 def expires_at
87   @token_mon.synchronize { @expires_at }
88 end
fetch_access_token(http)

when not available, it uses the http object to request new access and refresh tokens.

[show source]
    # File lib/httpx/plugins/oauth.rb
107 def fetch_access_token(http)
108   return access_token if access_token
109 
110   load(http)
111 
112   # always prefer refresh token grant if a refresh token is available
113   grant_type = @refresh_token ? "refresh_token" : @grant_type
114 
115   headers = {} # : Hash[String ,String]
116   form_post = {
117     "grant_type" => @grant_type,
118     "scope" => Array(@scope).join(" "),
119     "audience" => @audience,
120   }.compact
121 
122   # auth
123   case token_endpoint_auth_method
124   when "client_secret_post"
125     form_post["client_id"] = @client_id
126     form_post["client_secret"] = @client_secret
127   when "client_secret_basic"
128     headers["authorization"] = Authentication::Basic.new(@client_id, @client_secret).authenticate
129   end
130 
131   case grant_type
132   when "client_credentials"
133     # do nothing
134   when "refresh_token"
135     ref_token = refresh_token
136 
137     raise Error, "cannot use the `\"refresh_token\"` grant type without a refresh token" unless ref_token
138 
139     form_post["refresh_token"] = ref_token
140   end
141 
142   # POST /token
143   token_request = http.build_request("POST", token_endpoint, headers: headers, form: form_post)
144 
145   token_request.headers.delete("authorization") unless token_endpoint_auth_method == "client_secret_basic"
146 
147   token_response = http.skip_auth_header { http.request(token_request) }
148 
149   begin
150     token_response.raise_for_status
151   rescue HTTPError => e
152     @refresh_token = nil if e.response.status == 401 && (grant_type == "refresh_token")
153     raise e
154   end
155 
156   payload = token_response.json
157 
158   @token_mon.synchronize do
159     @refresh_token = payload.fetch("refresh_token", @refresh_token)
160     if (expires_in = payload["expires_in"])
161       @expires_at = Time.now.to_i + Integer(expires_in)
162     end
163     @access_token = payload["access_token"]
164   end
165 end
merge(other)

TODO: remove this after deprecating the ‘:oauth_session` option

[show source]
    # File lib/httpx/plugins/oauth.rb
168 def merge(other)
169   obj = dup
170 
171   case other
172   when OAuthSession
173     other.instance_variables.each do |ivar|
174       val = other.instance_variable_get(ivar)
175       next unless val
176 
177       obj.instance_variable_set(ivar, val)
178     end
179   when Hash
180     other.each do |k, v|
181       obj.instance_variable_set(:"@#{k}", v) if obj.instance_variable_defined?(:"@#{k}")
182     end
183   end
184   obj
185 end
reset!()
[show source]
    # File lib/httpx/plugins/oauth.rb
100 def reset!
101   @token_mon.synchronize do
102     @access_token = @expires_at = nil
103   end
104 end
token_endpoint()

returns the URL where to request access and refresh tokens from.

[show source]
   # File lib/httpx/plugins/oauth.rb
77 def token_endpoint
78   @token_endpoint || "#{@issuer}/token"
79 end
token_endpoint_auth_method()

returns the oauth-documented authorization method to use when requesting a token.

[show source]
   # File lib/httpx/plugins/oauth.rb
82 def token_endpoint_auth_method
83   @token_endpoint_auth_method || "client_secret_basic"
84 end