module ApiGuard::JwtAuth::RefreshJwtToken

Common module for refresh token functionality

Public Class Methods

authenticate_and_set_resource(resource_name) click to toggle source

Authenticate the JWT token and set resource

# 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_token() click to toggle source

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

# 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_resource() click to toggle source
# 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_token() click to toggle source

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

# 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) click to toggle source

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

# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source

authenticat———–

Calls superclass method
# 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) click to toggle source

Create a new refresh_token for the current resource

# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
Calls superclass method
# 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) click to toggle source

Generate and return unique refresh token for the resource

# 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) click to toggle source

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

# 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