Avoid sign-in after confirmation link click using devise gem?

12.3k Views Asked by At

I am using devise gem, after clicking on the confirmation link, I want to directly sign-in. At present it is asking to sign-in again.

Recently I have added the following in the devise initialize file:

config.allow_insecure_token_lookup = true
config.secret_key = 'a8d814803c0bcc735ce657adc77793459d00154cdd7532c13d3489600dc4e963f86e14beb593a32cbe9dbbe9197c9ce50a30102f363d90350052dc8d69930033'

Any suggestions?

5

There are 5 best solutions below

3
On

The config.allow_insecure_sign_in_after_confirmation flag is no longer supported in Devise.

While you should be aware of the possible security concerns of automatically logging users in when they confirm their account (http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/), for some apps the benefit in terms of user experience may be worth the security tradeoff.

After all, the security risk is that a) the user mis-types their email, b) they don't immediately correct their mistake, c) the email they typed corresponds to a valid and working email, d) the person who incorrectly receives the email opens it and clicks the link.

If this is an acceptable risk profile for your application, you can override the devise ConfirmationsController:

class ConfirmationsController < Devise::ConfirmationsController
  def show
    self.resource = resource_class.confirm_by_token(params[:confirmation_token])
    yield resource if block_given?

    if resource.errors.empty?
      set_flash_message(:notice, :confirmed) if is_flashing_format?
      sign_in(resource) # <= THIS LINE ADDED
      respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
    else
      respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render :new }
    end
  end
end

And route to it in your routes.rb:

devise_for :users, controllers: { confirmations: 'confirmations' }
0
On

Here you have how you can solve it.

This code will allow the user to automatically sign-in after confirming, only if is the first time confirming his/her account.

class ConfirmationsController < Devise::ConfirmationsController
  before_action :maybe_auto_sign_in, only: :show

  protected

  def after_confirmation_path_for(resource_name, resource)
    sign_in(resource) if @auto_sign_in
    super
  end

  private

  # Automatically sign in the user that confirmed his/her email first time.
  def maybe_auto_sign_in
    @auto_sign_in =
      User.first_time_confirming?(params[:confirmation_token])
  end
end

class User < ActiveRecord::Base
  def self.first_time_confirming?(confirmation_token)
    confirmation_token &&
      User.where(confirmation_token: confirmation_token, unconfirmed_email: nil)
          .exists?
  end
end
4
On

With more recent versions of Devise, you can do the following.

config/routes.rb:

devise_for :users, controllers: { confirmations: 'users/confirmations' }

app/controllers/users/confirmations_controller.rb:

class Users::ConfirmationsController < Devise::ConfirmationsController
  def show
    super do |resource|
      sign_in(resource)
    end
  end
end
0
On

Looking at mb21's answer, it should be

def show
  super do |resource|
    if resource.confirmation_sent_at > DateTime.now-2.hours && resource.errors.empty?
      sign_in(resource)
    end
  end
end

confirmation_sent_at is the time the email was sent to the user, as opposed to confirmed_at, which is the moment the user clicks the link, which is always within 2 hours of now on the server when it happens...

0
On

We wanted the user so sign in automatically if she clicks the link in the email 2 hours or less after user creation. Based on @Sjor's answer, we went with:

class ConfirmationsController < Devise::ConfirmationsController
  def show
    super do |resource|
      if resource.confirmed_at > DateTime.now-2.hours && resource.errors.empty?
        sign_in(resource)
      end
    end
  end
end