class PusherPlatform::Authenticator
Public Class Methods
new(instance_id, key_id, key_secret)
click to toggle source
# File lib/pusher-platform/authenticator.rb, line 8 def initialize(instance_id, key_id, key_secret) @instance_id = instance_id @key_id = key_id @key_secret = key_secret end
Public Instance Methods
authenticate(request, options)
click to toggle source
Takes a Rack request to the authorization endpoint and and handles it either returning a new access/refresh token pair, or an error.
@param request [Rack::Request] the request to authenticate @return the response object
# File lib/pusher-platform/authenticator.rb, line 19 def authenticate(request, options) form_data = Rack::Utils.parse_nested_query request.body.read grant_type = form_data['grant_type'] if grant_type == "client_credentials" return authenticate_with_client_credentials(options) elsif grant_type == "refresh_token" old_refresh_jwt = form_data['refresh_token'] return authenticate_with_refresh_token(old_refresh_jwt, options) else return response(401, { error: "unsupported_grant_type" }) end end
generate_access_token(options)
click to toggle source
# File lib/pusher-platform/authenticator.rb, line 35 def generate_access_token(options) now = Time.now.utc.to_i claims = { instance: @instance_id, iss: "api_keys/#{@key_id}", iat: now, exp: now + TOKEN_EXPIRY } claims.merge!({ sub: options[:user_id] }) unless options[:user_id].nil? claims.merge!({ su: true }) if options[:su] { token: JWT.encode(claims, @key_secret, 'HS256'), expires_in: TOKEN_EXPIRY } end
Private Instance Methods
authenticate_with_client_credentials(options)
click to toggle source
# File lib/pusher-platform/authenticator.rb, line 56 def authenticate_with_client_credentials(options) return respond_with_new_token_pair(options) end
authenticate_with_refresh_token(old_refresh_jwt, options)
click to toggle source
# File lib/pusher-platform/authenticator.rb, line 60 def authenticate_with_refresh_token(old_refresh_jwt, options) old_refresh_token = begin JWT.decode(old_refresh_jwt, @key_secret, true, { iss: "api_keys/#{@key_id}", verify_iss: true, }).first rescue => e error_description = if e.is_a?(JWT::InvalidIssuerError) "refresh token issuer is invalid" elsif e.is_a?(JWT::ImmatureSignature) "refresh token is not valid yet" elsif e.is_a?(JWT::ExpiredSignature) "refresh tokan has expired" else "refresh token is invalid" end return response(401, { error: "invalid_grant", error_description: error_description, # TODO error_uri }) end if old_refresh_token["refresh"] != true return response(401, { error: "invalid_grant", error_description: "refresh token does not have a refresh claim", # TODO error_uri }) end if options[:user_id] != old_refresh_token["sub"] return response(401, { error: "invalid_grant", error_description: "refresh token has an invalid user id", # TODO error_uri }) end return respond_with_new_token_pair(options) end
generate_refresh_token(options)
click to toggle source
# File lib/pusher-platform/authenticator.rb, line 118 def generate_refresh_token(options) now = Time.now.utc.to_i claims = { instance: @instance_id, iss: "api_keys/#{@key_id}", iat: now, refresh: true, sub: options[:user_id], } { token: JWT.encode(claims, @key_secret, 'HS256') } end
respond_with_new_token_pair(options)
click to toggle source
Creates a payload dictionary made out of access and refresh token pair and TTL for the access token.
@param user_id [String] optional id of the user, ignore for anonymous users @return [Hash] Payload as a hash
# File lib/pusher-platform/authenticator.rb, line 107 def respond_with_new_token_pair(options) access_token = generate_access_token(options)[:token] refresh_token = generate_refresh_token(options)[:token] return response(200, { access_token: access_token, token_type: "bearer", expires_in: TOKEN_EXPIRY, refresh_token: refresh_token, }) end
response(status, body)
click to toggle source
# File lib/pusher-platform/authenticator.rb, line 132 def response(status, body) return { status: status, json: body, } end