require 'httparty' module Alula class Oauth include HTTParty class << self # Has pseudo attr readers :client_id, :client_secret, :api_url, :debug def configure(**config) self.api_url = config[:api_url] self.client_id = config[:client_id] self.client_secret = config[:client_secret] self.debug = config[:debug] == true nil end def authenticate(username: nil, password: nil, grant_type: :password, scopes: nil) raise Alula::NotConfiguredError.new('did you forget to call Alula::Oauth.configure ?') unless api_url raise Alula::NotConfiguredError.new('no scopes specified') if grant_type.to_sym == :client_credentials && (scopes.nil? || scopes == '') opts = { body: { grant_type: grant_type.to_s, client_id: client_id, client_secret: client_secret, } } if grant_type == :password opts[:body][:username] = username if username opts[:body][:password] = password if password end opts[:body][:scope] = scopes if grant_type.to_sym == :client_credentials if self.debug opts[:debug_output] = Alula.logger # sets the HTTParty logger logger Alula.logger, :info end response = post(api_url + '/oauth/token', opts) if response.ok? Response.new(response.parsed_response) else Error.new(response.parsed_response) end end def refresh(refresh_token:, access_token:) opts = { body: { grant_type: 'refresh_token', client_id: client_id, client_secret: client_secret, refresh_token: refresh_token, }, headers: { 'Authorization:': "Bearer #{access_token}" } } if self.debug == true opts[:debug_output] = Alula.logger end response = post(api_url + '/oauth/token', opts) if response.ok? Response.new(response.parsed_response) else Error.new(response.parsed_response) end end %i(api_url client_id client_secret debug).each do |prop| define_method(prop) do RequestStore.store["alula_#{prop}"] end define_method("#{prop}=") do |value| RequestStore.store["alula_#{prop}"] = value end end end # Simple Oauth::Response reader object class Response attr_reader :token_type, :access_token, :expires_in, :expires_at, :refresh_token, :scope def initialize(attributes) @raw_response = attributes @token_type = attributes['token_type'] @access_token = attributes['access_token'] @expires_in = attributes['expires_in'] @expires_at = Time.now + @expires_in @refresh_token = attributes['refresh_token'] @scope = attributes['scope'] end end # Simple representation of an auth error class Error attr_reader :code, :error, :error_description, :raw_response def initialize(attributes) @raw_response = attributes @code = attributes['code'] @error = attributes['error'] @error_description = attributes['error_description'] || attributes['message'] end end end end