Module: ApiGuard::JwtAuth::Authentication

Defined in:
lib/api_guard/jwt_auth/authentication.rb

Overview

Common module for API authentication

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

Handle authentication of the resource dynamically



6
7
8
9
10
11
12
13
14
15
# File 'lib/api_guard/jwt_auth/authentication.rb', line 6

def method_missing(name, *args)
  method_name = name.to_s

  if method_name.start_with?('authenticate_and_set_')
    resource_name = method_name.split('authenticate_and_set_')[1]
    authenticate_and_set_resource(resource_name)
  else
    super
  end
end

Instance Method Details

#authenticate_and_set_resource(resource_name) ⇒ Object

Authenticate the JWT token and set resource



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/api_guard/jwt_auth/authentication.rb', line 18

def authenticate_and_set_resource(resource_name)
  @resource_name = resource_name

  @token = request.headers['Authorization']&.split('Bearer ')&.last
  return render_error(401, message: I18n.t('api_guard.access_token.missing')) unless @token

  authenticate_token

  # Render error response only if no resource found and no previous render happened
  render_error(401, message: I18n.t('api_guard.access_token.invalid')) if !current_resource && !performed?
rescue JWT::DecodeError => e
  if e.message == 'Signature has expired'
    render_error(401, message: I18n.t('api_guard.access_token.expired'))
  else
    render_error(401, message: I18n.t('api_guard.access_token.invalid'))
  end
end

#authenticate_tokenObject

Authenticate the resource with the ‘{resource_name}_id’ in the decoded JWT token and also, check for valid issued at time and not blacklisted

Also, set “current_{resource_name}” method and “@current_{resource_name}” instance variable for accessing the authenticated resource



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/api_guard/jwt_auth/authentication.rb', line 56

def authenticate_token
  return unless decode_token && @decoded_token[:"#{@resource_name}_id"].present?

  resource = @resource_name.classify.constantize.find_by(id: @decoded_token[:"#{@resource_name}_id"])

  self.class.send(:define_method, "current_#{@resource_name}") do
    instance_variable_get("@current_#{@resource_name}") || instance_variable_set("@current_#{@resource_name}", resource)
  end

  return if current_resource && valid_issued_at? && !blacklisted?

  render_error(401, message: I18n.t('api_guard.access_token.invalid'))
end

#current_resourceObject



70
71
72
73
74
# File 'lib/api_guard/jwt_auth/authentication.rb', line 70

def current_resource
  return unless respond_to?("current_#{@resource_name}")

  public_send("current_#{@resource_name}")
end

#decode_tokenObject

Decode the JWT token and don’t verify token expiry for refresh token API request



38
39
40
41
42
# File 'lib/api_guard/jwt_auth/authentication.rb', line 38

def decode_token
  # TODO: Set token refresh controller dynamic
  verify_token = (controller_name != 'tokens' || action_name != 'create')
  @decoded_token = decode(@token, verify_token)
end

#valid_issued_at?Boolean

Returns whether the JWT token is issued after the last password change Returns true if password hasn’t changed by the user

Returns:

  • (Boolean)


46
47
48
49
# File 'lib/api_guard/jwt_auth/authentication.rb', line 46

def valid_issued_at?
  return true unless ApiGuard.invalidate_old_tokens_on_password_change
  !current_resource.token_issued_at || @decoded_token[:iat] >= current_resource.token_issued_at.to_i
end