Module: ApiGuard::JwtAuth::RefreshJwtToken

Included in:
Test::ControllerHelper
Defined in:
lib/api_guard/jwt_auth/refresh_jwt_token.rb

Overview

Common module for refresh token functionality

Class Method Summary collapse

Class Method Details

.authenticate_and_set_resource(resource_name) ⇒ Object

Authenticate the JWT token and set resource



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 63

def self.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



111
112
113
114
115
116
117
118
119
120
121
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 111

def self.authenticate_token
  return unless decode_token

  resource = find_resource_from_token(@resource_name.classify.constantize)

  if resource && valid_issued_at?(resource) && !blacklisted?(resource)
    define_current_resource_accessors(resource)
  else
    render_error(401, message: I18n.t('api_guard.access_token.invalid'))
  end
end

.current_resourceObject



130
131
132
133
134
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 130

def self.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



83
84
85
86
87
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 83

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

.define_current_resource_accessors(resource) ⇒ Object

Defines “current_{resource_name}” method and “@current_{resource_name}” instance variable that returns “resource” value



99
100
101
102
103
104
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 99

def self.define_current_resource_accessors(resource)
  define_singleton_method("current_#{@resource_name}") do
    instance_variable_get("@current_#{@resource_name}") ||
      instance_variable_set("@current_#{@resource_name}", resource)
  end
end

.destroy_all_refresh_tokens(resource) ⇒ Object



39
40
41
42
43
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 39

def self.destroy_all_refresh_tokens(resource)
  return unless refresh_token_enabled?(resource)

  refresh_tokens_for(resource).destroy_all
end

.find_refresh_token_of(resource, refresh_token) ⇒ Object



20
21
22
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 20

def self.find_refresh_token_of(resource, refresh_token)
  refresh_tokens_for(resource).find_by_token(refresh_token)
end

.find_resource_from_token(resource_class) ⇒ Object



123
124
125
126
127
128
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 123

def self.find_resource_from_token(resource_class)
  resource_id = @decoded_token[:"#{@resource_name}_id"]
  return if resource_id.blank?

  resource_class.find_by(id: resource_id)
end

.method_missing(name, *args) ⇒ Object

authenticat———–



47
48
49
50
51
52
53
54
55
56
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 47

def self.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

.new_refresh_token(resource) ⇒ Object

Create a new refresh_token for the current resource



33
34
35
36
37
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 33

def self.new_refresh_token(resource)
  return unless refresh_token_enabled?(resource)

  refresh_tokens_for(resource).create(token: uniq_refresh_token(resource)).token
end

.refresh_token_association(resource) ⇒ Object



7
8
9
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 7

def self.refresh_token_association(resource)
  resource.class.refresh_token_association
end

.refresh_token_enabled?(resource) ⇒ Boolean

Returns:

  • (Boolean)


11
12
13
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 11

def self.refresh_token_enabled?(resource)
  refresh_token_association(resource).present?
end

.refresh_tokens_for(resource) ⇒ Object



15
16
17
18
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 15

def self.refresh_tokens_for(resource)
  refresh_token_association = refresh_token_association(resource)
  resource.send(refresh_token_association)
end

.respond_to_missing?(method_name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


58
59
60
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 58

def self.respond_to_missing?(method_name, include_private = false)
  method_name.to_s.start_with?('authenticate_and_set_') || super
end

.uniq_refresh_token(resource) ⇒ Object

Generate and return unique refresh token for the resource



25
26
27
28
29
30
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 25

def self.uniq_refresh_token(resource)
  loop do
    random_token = SecureRandom.urlsafe_base64
    return random_token unless refresh_tokens_for(resource).exists?(token: random_token)
  end
end

.valid_issued_at?(resource) ⇒ 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)


91
92
93
94
95
# File 'lib/api_guard/jwt_auth/refresh_jwt_token.rb', line 91

def self.valid_issued_at?(resource)
  return true unless ApiGuard.invalidate_old_tokens_on_password_change

  !resource.token_issued_at || @decoded_token[:iat] >= resource.token_issued_at.to_i
end