Forked from josevalim/1_unsafe_token_authenticatable.rb
Created
February 21, 2017 18:24
-
-
Save HusseinElMotayam/800f2515dfb636a5451cf922e0ed1557 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This snippet shows how TokenAuthenticatable works in Devise today. | |
# In case you want to maintain backwards compatibility, you can ditch | |
# devise's token mechanism in favor of this hand-rolled one. If not, | |
# it is recommended to migrate to the mechanism defined in the following | |
# snippet (2_safe_token_authenticatable.rb). | |
# | |
# In both snippets, we are assuming the User is the Devise model. | |
class User < ActiveRecord::Base | |
# You likely have this before callback set up for the token. | |
before_save :ensure_authentication_token | |
def ensure_authentication_token | |
if authentication_token.blank? | |
self.authentication_token = generate_authentication_token | |
end | |
end | |
private | |
def generate_authentication_token | |
loop do | |
token = Devise.friendly_token | |
break token unless User.where(authentication_token: token).first | |
end | |
end | |
end | |
# With a token setup, all you need to do is override | |
# your application controller to also consider token | |
# lookups: | |
class ApplicationController < ActionController::Base | |
# This is our new function that comes before Devise's one | |
before_filter :authenticate_user_from_token! | |
# This is Devise's authentication | |
before_filter :authenticate_user! | |
private | |
# For this example, we are simply using token authentication | |
# via parameters. However, anyone could use Rails's token | |
# authentication features to get the token from a header. | |
def authenticate_user_from_token! | |
user_token = params[:user_token].presence | |
user = user_token && User.find_by_authentication_token(user_token.to_s) | |
if user | |
# Notice we are passing store false, so the user is not | |
# actually stored in the session and a token is needed | |
# for every request. If you want the token to work as a | |
# sign in token, you can simply remove store: false. | |
sign_in user, store: false | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# We could make the authentication mechanism above a bit more safe | |
# by requiring a token **AND** an e-mail for token authentication. | |
# The code in the model looks the same, we just need to slightly | |
# change the controller: | |
class ApplicationController < ActionController::Base | |
# This is our new function that comes before Devise's one | |
before_filter :authenticate_user_from_token! | |
# This is Devise's authentication | |
before_filter :authenticate_user! | |
private | |
def authenticate_user_from_token! | |
user_email = params[:user_email].presence | |
user = user_email && User.find_by_email(user_email) | |
# Notice how we use Devise.secure_compare to compare the token | |
# in the database with the token given in the params, mitigating | |
# timing attacks. | |
if user && Devise.secure_compare(user.authentication_token, params[:user_token]) | |
sign_in user, store: false | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment