class OAuth2::AccessToken
rubocop:disable Metrics/ClassLength
def [](key)
-
key(String) -- entry key to Hash
def [](key) @params[key] end
def configure_authentication!(opts, verb)
def configure_authentication!(opts, verb) mode_opt = options[:mode] mode = if mode_opt.respond_to?(:call) mode_opt.call(verb) elsif mode_opt.is_a?(Hash) key = verb.to_sym # Try symbol key first, then string key; default to :header when missing mode_opt[key] || mode_opt[key.to_s] || :header else mode_opt end case mode when :header opts[:headers] ||= {} opts[:headers].merge!(headers) when :query # OAuth 2.1 note: Bearer tokens in the query string are omitted from the spec due to security risks. # Prefer the default :header mode whenever possible. opts[:params] ||= {} opts[:params][options[:param_name]] = token when :body opts[:body] ||= {} if opts[:body].is_a?(Hash) opts[:body][options[:param_name]] = token else opts[:body] += "&#{options[:param_name]}=#{token}" end # @todo support for multi-part (file uploads) else raise("invalid :mode option of #{mode}") end end
def convert_expires_at(expires_at)
def convert_expires_at(expires_at) Time.iso8601(expires_at.to_s).to_i rescue ArgumentError expires_at.to_i end
def delete(path, opts = {}, &block)
- See: AccessToken#request -
def delete(path, opts = {}, &block) request(:delete, path, opts, &block) end
def expired?
-
(Boolean)- true if the token is expired, false otherwise
def expired? expires? && (expires_at <= Time.now.to_i) end
def expires?
-
(Boolean)-
def expires? !!@expires_at end
def extra_tokens_warning(supported_keys, key)
def extra_tokens_warning(supported_keys, key) return if OAuth2.config.silence_extra_tokens_warning return if supported_keys.length <= 1 warn("OAuth2::AccessToken.from_hash: `hash` contained more than one 'token' key (#{supported_keys}); using #{key.inspect}.") end
def from_hash(client, hash)
- Note: - If snaky key conversion is being used, token_name needs to match the converted key.
Note: - For "soon-to-expire"/"clock-skew" functionality see the `:expires_latency` option.
Note: - If no token keys are present, a warning will be issued unless
Note: - If multiple token keys are present, a warning will be issued unless
Note: - The method will use the first found token key in the following order:
Returns:
-
(OAuth2::AccessToken)- the initialized AccessToken
Options Hash:
(**hash)-
'expires_latency'(Integer, String) -- seconds to reduce token validity by -
'expires_at'(Integer, String) -- epoch time in seconds when token expires -
'expires_in'(Integer, String) -- number of seconds until token expires -
'refresh_token'(String) -- the refresh token value -
'token'(String) -- alternative key for the access token value -
'id_token'(String) -- alternative key for the access token value -
'access_token'(String) -- the access token value
Parameters:
-
hash(Hash) -- a hash containing the token and other properties -
client(OAuth2::Client) -- the OAuth2::Client instance
def from_hash(client, hash) fresh = hash.dup # If token_name is present, then use that key name if fresh.key?(:token_name) t_key = fresh[:token_name] no_tokens_warning(fresh, t_key) else # Otherwise, if one of the supported default keys is present, use whichever has precedence supported_keys = TOKEN_KEY_LOOKUP & fresh.keys t_key = supported_keys[0] extra_tokens_warning(supported_keys, t_key) end # :nocov: # TODO: Get rid of this branching logic when dropping Hashie < v3.2 token = if !defined?(Hashie::VERSION) # i.e. <= "1.1.0"; the first Hashie to ship with a VERSION constant warn("snaky_hash and oauth2 will drop support for Hashie v0 in the next major version. Please upgrade to a modern Hashie.") # There is a bug in Hashie v0, which is accounts for. fresh.delete(t_key) || fresh[t_key] || "" else fresh.delete(t_key) || "" end # :nocov: new(client, token, fresh) end
def from_kvform(client, kvform)
-
(AccessToken)- the initialized AccessToken
Parameters:
-
kvform(String) -- the application/x-www-form-urlencoded string -
client(Client) -- the OAuth2::Client instance
def from_kvform(client, kvform) from_hash(client, Rack::Utils.parse_query(kvform)) end
def get(path, opts = {}, &block)
- See: AccessToken#request -
def get(path, opts = {}, &block) request(:get, path, opts, &block) end
def headers
def headers {"Authorization" => options[:header_format] % token} end
def initialize(client, token, opts = {})
(**opts)-
:token_name(String) -- the name of the response parameter that identifies the access token -
:param_name(String) -- the parameter name to use for transmission of the -
:header_format(String) -- the string format to use for the Authorization header -
:mode(Symbol, Hash, or callable) -- the transmission mode of the Access Token parameter value: -
:expires_latency(FixNum, String) -- the number of seconds by which AccessToken validity will be reduced to offset latency, @version 2.0+ -
:expires_at(FixNum, String) -- the epoch time in seconds in which AccessToken will expire -
:expires_in(FixNum, String) -- the number of seconds in which the AccessToken will expire -
:refresh_token(String) -- the refresh_token value
Other tags:
- Example: Verb-dependent Hash mode -
Parameters:
-
opts(Hash) -- the options to create the Access Token with -
token(String) -- the Access Token value (optional, may not be used in refresh flows) -
client(Client) -- the OAuth2::Client instance
Other tags:
- Note: - If no token is provided, the AccessToken will be considered invalid.
Note: - For "soon-to-expire"/"clock-skew" functionality see the `:expires_latency` option.
def initialize(client, token, opts = {}) @client = client @token = token.to_s opts = opts.dup %i[refresh_token expires_in expires_at expires_latency].each do |arg| instance_variable_set("@#{arg}", opts.delete(arg) || opts.delete(arg.to_s)) end no_tokens = (@token.nil? || @token.empty?) && (@refresh_token.nil? || @refresh_token.empty?) if no_tokens if @client.options[:raise_errors] raise Error.new({ error: "OAuth2::AccessToken has no token", error_description: "Options are: #{opts.inspect}", }) elsif !OAuth2.config.silence_no_tokens_warning warn("OAuth2::AccessToken has no token") end end # @option opts [Fixnum, String] :expires is deprecated @expires_in ||= opts.delete("expires") @expires_in &&= @expires_in.to_i @expires_at &&= convert_expires_at(@expires_at) @expires_latency &&= @expires_latency.to_i @expires_at ||= Time.now.to_i + @expires_in if @expires_in && !@expires_in.zero? @expires_at -= @expires_latency if @expires_latency @options = { mode: opts.delete(:mode) || :header, header_format: opts.delete(:header_format) || "Bearer %s", param_name: opts.delete(:param_name) || "access_token", } @options[:token_name] = opts.delete(:token_name) if opts.key?(:token_name) @params = opts end
def no_tokens_warning(hash, key)
def no_tokens_warning(hash, key) return if OAuth2.config.silence_no_tokens_warning return if key && hash.key?(key) warn(%[ ::AccessToken#from_hash key mismatch. token_name (#{key}) is not found in (#{hash.keys}) y need to set `snaky: false`. See inline documentation for more info. ]) end
def patch(path, opts = {}, &block)
- See: AccessToken#request -
def patch(path, opts = {}, &block) request(:patch, path, opts, &block) end
def post(path, opts = {}, &block)
- See: AccessToken#request -
def post(path, opts = {}, &block) request(:post, path, opts, &block) end
def put(path, opts = {}, &block)
- See: AccessToken#request -
def put(path, opts = {}, &block) request(:put, path, opts, &block) end
def refresh(params = {}, access_token_opts = {}, &block)
- Note: - current token's options are carried over to the new AccessToken
Returns:
-
(OAuth2::AccessToken)- a new AccessToken instance
Other tags:
- Yieldparam: opts - The options hash that can be modified
Other tags:
- Yield: - The block to modify the refresh token request options
Parameters:
-
access_token_opts(Hash) -- options that will be passed to the AccessToken initialization -
params(Hash) -- additional params to pass to the refresh token request
def refresh(params = {}, access_token_opts = {}, &block) raise OAuth2::Error.new({error: "A refresh_token is not available"}) unless refresh_token params[:grant_type] = "refresh_token" params[:refresh_token] = refresh_token new_token = @client.get_token(params, access_token_opts, &block) new_token.options = options if new_token.refresh_token # Keep it if there is one else new_token.refresh_token = refresh_token end new_token end
def request(verb, path, opts = {}, &block)
- See: OAuth2::Client#request -
Returns:
-
(OAuth2::Response)- the response from the request
Other tags:
- Yieldparam: req - The request object that can be modified
Other tags:
- Yield: - The block to modify the request
Options Hash:
(**opts)-
:headers(Hash) -- request headers -
:body(Hash, String) -- the request body -
:params(Hash) -- additional URL parameters
Parameters:
-
opts(Hash) -- the options to make the request with -
path(String) -- the HTTP URL path of the request -
verb(Symbol) -- the HTTP request method
def request(verb, path, opts = {}, &block) configure_authentication!(opts, verb) @client.request(verb, path, opts, &block) end
def revoke(params = {}, &block)
- See: https://datatracker.ietf.org/doc/html/rfc7009#section-2.1 -
See: https://datatracker.ietf.org/doc/html/rfc7009 -
Other tags:
- Note: - If the server responds with HTTP status code 503, your code must
Note: - If the token passed to the request
Note: - If the token passed to the request
Raises:
-
(OAuth2::Error)- if token_type_hint is invalid or the specified token is not available
Other tags:
- Api: - public
Returns:
-
(OAuth2::Response)- OAuth2::Response instance
Other tags:
- Yieldparam: req - The request object that can be modified
Other tags:
- Yield: - The block is passed the request being made, allowing customization
Options Hash:
(**params)-
:token_method(Symbol) -- overrides OAuth2::Client#options[:token_method] -
:token_type_hint(String, Symbol, nil) -- hint about which token to revoke
Parameters:
-
params(Hash) -- additional parameters to be sent during revocation
def revoke(params = {}, &block) token_type_hint_orig = params.delete(:token_type_hint) token_type_hint = nil revoke_token = case token_type_hint_orig when "access_token", :access_token token_type_hint = "access_token" token when "refresh_token", :refresh_token token_type_hint = "refresh_token" refresh_token when nil if token token_type_hint = "access_token" token elsif refresh_token token_type_hint = "refresh_token" refresh_token end else raise OAuth2::Error.new({error: "token_type_hint must be one of [nil, :refresh_token, :access_token], so if you need something else consider using a subclass or entirely custom AccessToken class."}) end raise OAuth2::Error.new({error: "#{token_type_hint || "unknown token type"} is not available for revoking"}) unless revoke_token && !revoke_token.empty? @client.revoke_token(revoke_token, token_type_hint, params, &block) end
def to_hash
-
(Hash)- a hash of AccessToken property values
Other tags:
- Note: - Don't return expires_latency because it has already been deducted from expires_at
def to_hash hsh = { access_token: token, refresh_token: refresh_token, expires_at: expires_at, mode: options[:mode], header_format: options[:header_format], param_name: options[:param_name], } hsh[:token_name] = options[:token_name] if options.key?(:token_name) # TODO: Switch when dropping Ruby < 2.5 support # params.transform_keys(&:to_sym) # Ruby 2.5 only # Old Ruby transform_keys alternative: sheesh = @params.each_with_object({}) { |(k, v), memo| memo[k.to_sym] = v } sheesh.merge(hsh) end