6

I'm trying to make signed up users to take some actions on my website, so I want to send them, by e-mail, a link directly to this action.

The problem is that I want them to be automatically logged in when clicking on this link.

I can do something obvious as creating an unique token and pass it through the url mysite.com/my_funky_action?login_bypass_token=af123fa127ba32 but this seems to me as a problem "solved many times before"

So, there is a simple way out there to do this using rails / devise? I've searched on devise documentation without success.

Pedro Bernardes
  • 706
  • 1
  • 8
  • 20
  • *"I can do something obvious as creating an unique token and pass it through the url"*: why look for anything simpler than the obvious way? – D-side May 31 '15 at 21:07
  • Because there is probably something ready, maybe hidden on devise code... why reinvent the wheel? – Pedro Bernardes May 31 '15 at 21:23
  • 1
    Devise deprecated and later removed the ability to sign on from a confirmation email because it's insecure. http://stackoverflow.com/questions/18655334/avoid-sign-in-after-confirmation-link-click-using-devise-gem – SteveTurczyn May 31 '15 at 21:33

2 Answers2

3

Using as basis the code from devise's recoverable, I did this

model:

class User < ActiveRecord::Base
    def set_login_bypass_token
        raw, enc = Devise.token_generator.generate(User, :login_bypass_token)
        self.login_bypass_token = enc
        self.login_bypass_token_set_at = Time.now.utc
        self.save(validate: false)
        raw
     end

     def self.by_bypass_token(token)
         original_token = Devise.token_generator.digest(self, :login_bypass_token, token)
         User.find_by(:login_bypass_token => original_token)
     end
end

mailer:

class SomeMailer < ActionMailer::Base
    def send_something
        ...
        @login_bypass_token = @user.set_login_bypass_token
        ...
    end
end

application_controller:

class ApplicationController < ActionController::Base
    layout :application_layout

    protect_from_forgery with: :exception
    before_action :bypass_login
    before_action :authenticate_user!

    private
        def bypass_login
            if params[:login_bypass_token]
                user = User.by_bypass_token(params[:login_bypass_token])
                sign_in(user, :bypass => true) if user
                redirect_to request.path
            end
        end
end

email template (in haml)

= link_to 'View this awesome page without login!', awesomeness_url(login_bypass_token: @login_bypass_token)
Pedro Bernardes
  • 706
  • 1
  • 8
  • 20
0

Generally not a good thing to do.

If you don't use a token, that means you'd need to build a path that includes the email address in clear, e.g.

http://my_app.com/special_action?email=john@sample.com

Given that, anybody would be able to sign on as any registered user simply by sending a url structured as the above, substituting whatever email they want.

Go for a token, make sure it expires when used or after the shortest time you can get away with.

SteveTurczyn
  • 36,057
  • 6
  • 41
  • 53