Skip to content

Instantly share code, notes, and snippets.

@desheikh
Created September 28, 2016 11:55
Show Gist options
  • Save desheikh/0c47a78b01eef460b5df5838dd1ee6e1 to your computer and use it in GitHub Desktop.
Save desheikh/0c47a78b01eef460b5df5838dd1ee6e1 to your computer and use it in GitHub Desktop.
Simple devise token authentication strategy using email + token
# config/locales/devise.en.yml
en:
devise:
failure:
invalid_token: "Invalid authentication token."
# config/initializers/devise.rb
Devise.setup do |config|
require 'devise/strategies/token_authenticatable'
config.warden do |manager|
manager.default_strategies(scope: :user).unshift :token_authenticatable
end
end
# lib/devise/models/token_authenticatable.rb
require 'devise/strategies/token_authenticatable'
module Devise
module Models
module TokenAuthenticatable
extend ActiveSupport::Concern
included do
before_save :ensure_authentication_token
end
def self.required_fields(_klass)
[:authentication_token]
end
def reset_authentication_token
self.authentication_token = self.class.authentication_token
end
def reset_authentication_token!
reset_authentication_token
save(validate: false)
end
def ensure_authentication_token
reset_authentication_token if authentication_token.blank?
end
def ensure_authentication_token!
reset_authentication_token! if authentication_token.blank?
end
module ClassMethods
def authentication_token
loop do
token = Devise.friendly_token(30)
break token unless to_adapter.find_first(authentication_token: token)
end
end
end
end
end
end
# lib/devise/strategies/token_authenticatable.rb
require 'devise/strategies/base'
module Devise
module Strategies
class TokenAuthenticatable < Authenticatable
def store?
false
end
def valid?
email.present? && token.present?
end
def authenticate!
request.env['devise.skip_trackable'] = true
valid_authentication? ? success!(resource) : fail(:invalid_token)
end
private
def email
params["#{mapping.name}_email"] || request.headers['X-USER-EMAIL']
end
def token
params["#{mapping.name}_token"] || request.headers['X-USER-TOKEN']
end
def resource
@resource ||= mapping.to.find_by_email(email)
end
def valid_authentication?
resource && Devise.secure_compare(resource.authentication_token, token)
end
end
end
end
Warden::Strategies.add(:token_authenticatable, Devise::Strategies::TokenAuthenticatable)
# app/models/user.rb
require 'devise/models/token_authenticatable'
devise :token_authenticatable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment