class HaveAPI::Authentication::OAuth2::Provider
OAuth2
authentication and authorization provider
Must be configured with {Config} using {OAuth2.with_config}.
Attributes
config[R]
@return [Config]
Public Class Methods
new(server, v, cfg)
click to toggle source
Calls superclass method
HaveAPI::Authentication::Base::new
# File lib/haveapi/authentication/oauth2/provider.rb, line 76 def initialize(server, v, cfg) @config = cfg.new(self, server, v) super(server, v) end
with_config(cfg)
click to toggle source
Configure the OAuth2
provider @param cfg [Config]
# File lib/haveapi/authentication/oauth2/provider.rb, line 62 def self.with_config(cfg) Module.new do define_singleton_method(:new) do |*args| Provider.new(*args, cfg) end end end
Public Instance Methods
authenticate(request)
click to toggle source
# File lib/haveapi/authentication/oauth2/provider.rb, line 115 def authenticate(request) tokens = [ request.params['access_token'], token_from_authorization_header(request), token_from_haveapi_header(request) ].compact token = case tokens.length when 0 nil when 1 tokens.first else raise 'Too many oauth2 tokens' end token && config.find_user_by_access_token(request, token) end
describe()
click to toggle source
# File lib/haveapi/authentication/oauth2/provider.rb, line 147 def describe desc = <<-END OAuth2 authorization provider. While OAuth2 support in HaveAPI clients is limited, it is possible to use your API as an authentication source and to use OAuth2 tokens to access the API. HaveAPI partially implements RFC 6749: authorization response type "code" and token grant types "authorization_code" and "refresh_token". Other response and grant types are not supported at this time. The access token can be passed as bearer token according to RFC 6750, or using a custom HTTP header when the Authorization header is not practical. The access and refresh tokens can be revoked as per RFC 7009. END { description: desc, http_header: config.http_header, authorize_url: @authorize_url, authorize_path: @authorize_path, token_url: @token_url, token_path: @token_path, revoke_url: @revoke_url, revoke_path: @revoke_path } end
register_routes(sinatra, prefix)
click to toggle source
# File lib/haveapi/authentication/oauth2/provider.rb, line 85 def register_routes(sinatra, prefix) @authorize_path = File.join(prefix, 'authorize') @token_path = File.join(prefix, 'token') @revoke_path = File.join(prefix, 'revoke') base_url = config.base_url @authorize_url = File.join(base_url, @authorize_path) @token_url = File.join(base_url, @token_path) @revoke_url = File.join(base_url, @revoke_path) that = self sinatra.get @authorize_path do that.authorization_endpoint(self).call(request.env) end sinatra.post @authorize_path do that.authorization_endpoint(self).call(request.env) end sinatra.post @token_path do that.token_endpoint(self).call(request.env) end sinatra.post @revoke_path do that.revoke_endpoint(self).call(request.env) end end
revoke_endpoint(handler)
click to toggle source
# File lib/haveapi/authentication/oauth2/provider.rb, line 289 def revoke_endpoint(handler) RevokeEndpoint.new do |req, _res| ret = config.handle_post_revoke( handler.request, req.token, token_type_hint: req.token_type_hint ) case ret when :revoked # ok when :unsupported req.unsupported_token_type! else raise Rack::OAuth2::Server::Abstract::ServerError end end end
setup()
click to toggle source
# File lib/haveapi/authentication/oauth2/provider.rb, line 81 def setup @server.allow_header(config.http_header) end
token_endpoint(handler)
click to toggle source
# File lib/haveapi/authentication/oauth2/provider.rb, line 237 def token_endpoint(handler) Rack::OAuth2::Server::Token.new do |req, res| client = config.find_client_by_id(req.client_id) req.invalid_client! if client.nil? || !client.check_secret(req.client_secret) res.access_token = case req.grant_type when :authorization_code authorization = config.find_authorization_by_code(client, req.code) if authorization.nil? || !authorization.check_code_validity(req.redirect_uri) req.invalid_grant! end if authorization.code_challenge && authorization.code_challenge_method req.verify_code_verifier!( authorization.code_challenge, authorization.code_challenge_method.to_sym ) end access_token, expires_at, refresh_token = config.get_tokens(authorization, handler.request) bearer_token = Rack::OAuth2::AccessToken::Bearer.new( access_token:, expires_in: expires_at - Time.now ) bearer_token.refresh_token = refresh_token if refresh_token bearer_token when :refresh_token authorization = config.find_authorization_by_refresh_token(client, req.refresh_token) if authorization.nil? req.invalid_grant! end access_token, expires_at, refresh_token = config.refresh_tokens(authorization, handler.request) bearer_token = Rack::OAuth2::AccessToken::Bearer.new( access_token:, expires_in: expires_at - Time.now ) bearer_token.refresh_token = refresh_token if refresh_token bearer_token else # :password, :client_credentials req.unsupported_grant_type! end end end
token_from_haveapi_header(request)
click to toggle source
# File lib/haveapi/authentication/oauth2/provider.rb, line 143 def token_from_haveapi_header(request) request.env[header_to_env(config.http_header)] end
Private Instance Methods
header_to_env(header)
click to toggle source
# File lib/haveapi/authentication/oauth2/provider.rb, line 310 def header_to_env(header) "HTTP_#{header.upcase.gsub('-', '_')}" end