8

My User.rb:

class User < ActiveRecord::Base

    devise :database_authenticatable, :registerable,:confirmable,:token_authenticatable,
     :recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:name]

My routes:

devise_for :users, :controllers => { :sessions => "sessions", :confirmations => "confirmations", :passwords => "passwords", :registrations => "registrations" }

My ConfirmationsController is a standard controller but with different redirect.

I have link on my email like:

/users/confirmation?confirmation_token=167bad44a15e02b0bd570b51e1bf927b88368d8855d92b9833a24017a2bad4be

In database user has

confirmation_token:167bad44a15e02b0bd570b51e1bf927b88368d8855d92b9833a24017a2bad4be

But when i click on that link i only see page with:

Resend confirmation instructions
 Confirmation token is invalid

What i dont do - what else i have to set.

CONFIRMATIONCONTROLLER:

def resource_params
 params.require(:user).permit(:confirmation_token)
   end
   private :resource_params


  def show
self.resource = resource_class.confirm_by_token(params[:confirmation_token])

if resource.errors.empty?
  set_flash_message(:notice, :confirmed) if is_navigational_format?
  sign_in(resource_name, resource)
  session['new_user'] = true
  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

  protected
    # The path used after resending confirmation instructions.
    def after_resending_confirmation_instructions_path_for(resource_name)
      new_registration_path(resource_name)
    end

I say "standard controller" because when i remove it and do not use custom controller problem is that same.

Wordica
  • 2,427
  • 3
  • 31
  • 51
  • Post your "standard" overridden controller code. – TheIrishGuy Aug 22 '13 at 20:22
  • and? Is there some bug or what... i change token to abcde in database and in url - and nothing change – Wordica Aug 22 '13 at 21:04
  • This might not solve the whole problem, but if you just want to redirect to a different path after confirmation you should not copy/paste the entire method. You should override the protected method `after_confirmation_path_for` to return the path you want. – Ross Allen Aug 22 '13 at 21:15
  • yes it doesnt change nothing - confirmed_at: nil . Devise just cant confirm account with token – Wordica Aug 22 '13 at 21:17

3 Answers3

17

Which version of devise are you using? If you're on 3.1.0 or higher, this behavior is expected:

CHANGELOG.md

The tokens that are stored in the database are not supposed to match the tokens that you send in the confirmation e-mails. See devise/lib/devise/models/confirmable.rb, which now contains the following:

def confirm_by_token(confirmation_token)
  original_token     = confirmation_token
  confirmation_token = Devise.token_generator.digest(self, :confirmation_token, confirmation_token)

  confirmable = find_or_initialize_with_error_by(:confirmation_token, confirmation_token)

As you can see, the token that you pass in via query string params is consumed by the Devise.token_generator, and the result of that operation is what's compared with the token in the database to discover the user record.

It looks like it's temporarily possible (in 3.1 but not 3.2) to turn this off by setting

config.allow_insecure_token_lookup = true

in your devise initializer. But the default behavior has been changed to make devise more secure. See this blog post for a complete rundown of the security improvements in devise 3.1, including this change.

gregates
  • 6,607
  • 1
  • 31
  • 31
  • According to the blog cited, this fix will be available only temporarily (http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/). What's the permanent solution? – Erik Trautman May 06 '14 at 01:29
  • That's not a fix, it's a workaround for people who are upgrading from older versions. You may not want a deploy with Devise 3.1 to invalidate existing confirmation tokens that should be valid. If your application has customized the confirmation so that it doesn't work with Devise >= 3.1, the "fix" is to make it work with the new, encrypted tokens. Since that means un-doing or re-doing customizations, that's outside the scope of this question. I can only explain what they're doing in 3.1 and why. – gregates May 06 '14 at 15:25
5

You can use the solution below (setting config.allow_insecure_token_lookup = true) but, according to the Devise changelog, this will be only available temporarily.

The problem likely arose because you ran the devise generator to dump all of their views into yours back before they made these changes. Then you updated your Devise gem and all the back end stuff changed but your views didn't. Now all your devise-related views and mailers are out of date and won't work with the new token styles.

You can see the new emails at: https://github.com/plataformatec/devise/tree/master/app/views/devise/mailer. The major change is changing this line:

<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %></p>

to

<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>

The main difference is @resource.confirmation_token becomes just @token.

Erik Trautman
  • 5,883
  • 2
  • 27
  • 35
2

I change @resource.confirmation_token to @token then it works.

scottxu
  • 913
  • 1
  • 7
  • 20