Skip to content

Instantly share code, notes, and snippets.

@lardawge
Created March 1, 2021 17:15
Show Gist options
  • Save lardawge/088a0fc720665fc632ba20ba5c880d7e to your computer and use it in GitHub Desktop.
Save lardawge/088a0fc720665fc632ba20ba5c880d7e to your computer and use it in GitHub Desktop.
module Devise
module Strategies
class Token < Base
attr_reader :email, :token
def initialize(env, scope = nil)
super
return unless auth = ActionController::HttpAuthentication::Token.token_and_options(request)
@email = auth.last[:email]
@token = auth.first
env['devise.skip_trackable'] = @token.present?
end
def valid?
token
end
def authenticate!
resource = scope.to_s.classify.constantize.find_by(api_token: token)
if secure_compare(resource.try(:api_token))
success!(resource)
else
fail!('Invalid user email or token')
end
end
private
# constant-time comparison algorithm to prevent timing attacks
def secure_compare(api_token)
return false if api_token.blank? || token.blank? || api_token.bytesize != token.bytesize
unpacked_token = api_token.unpack "C#{api_token.bytesize}"
res = 0
token.each_byte { |byte| res |= byte ^ unpacked_token.shift }
res.zero?
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment