Closed yamini0312 closed 11 months ago
Are you upgrading from Devise 3.4 to 4.0? I don't think anything changed around those versions much, but in 3.1 the way tokens are generated changed, see http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/.
It is possible you were still storing tokens the old way previously if you had any custom implementation that was calling generate_confirmation_token
yourself.
If that's not the case, I'm gonna need some more code examples to understand what is happening, because these are pretty old versions. (that we're soon dropping support for) Also, before going to 4.0 I'd recommend upgrading to the latest 3.x version (3.5.10 apparently)
Thank you for the response @carlosantoniodasilva
Here is the logic which i have used. When user Signup, I am sending confirmation email :
def send_confirmation_email(force = false)
unless @raw_confirmation_token
if confirmation_token
@raw_confirmation_token = confirmation_token
else
generate_confirmation_token!
self.save
end
end
opts = pending_reconfirmation? ? { :to => unconfirmed_email } : { }
opts[:force] = force
if force == true
confirmation_token, @raw_confirmation_token = Devise.token_generator.generate(self.class, :confirmation_token)
if self.update_attributes(confirmation_token: @raw_confirmation_token)
devise_mailer.send(:forced_confirmation_instructions, self, confirmation_token, opts).deliver
end
else
send_devise_notification(:confirmation_instructions, @raw_confirmation_token, opts)
end
end
In Devise 4.0.0, above code is storing the plaintext token in the db with user record using generate_confirmation_token! (In devise 3.4.0, it was storing 64 char token).
When user confirm the email by clicking on link, below code excecutes.
def find_unconfirmed_confirmable
original_token = params[:confirmation_token]
confirmation_token = Devise.token_generator.digest(User, :confirmation_token, original_token)
@confirmable = User.find_or_initialize_with_error_by(:confirmation_token, confirmation_token)
if !@confirmable.new_record?
@confirmable.only_if_unconfirmed { return @confirmable }
end
nil
end
So here what is happening is, it is trying to match with the 64 char token with user record but everytime it is getting null value because plaintext is stored in db with user record.
Is it safe to store plaintext in the db and compare the plaintext while confirming the email instead of 64 char token?
Thank you!
Is it safe to store plaintext in the db and compare the plaintext while confirming the email instead of 64 char token?
It should be fine for confirmation. It appears that this changed back on Devise 3.5.2, which I had forgotten: https://github.com/heartcombo/devise/commit/bc6361ab9bd809d8bf51fe2092da6fcb8b495adc.
In other words, we store the plain text generated code for confirmation (but not for reset password), because we no longer sign the user in automatically during the confirmation flow.
In other words, there's probably no need to use the token generator in your custom implementation with the upgrade to v4.0 and above.
Environment
when I use generate_confirmation_token! during signup process, it is storing plaintext confirmation_token with the user record in table. I want to store it as 64 char confirmation_token with user record so, while confirming an email it should match with Devise.token_generator.digest(User, :confirmation_token, original_token). currently this method trying to match the record which has 64 char but in my db it has stored as plaintext so the user record is not matching with confirmation token.
On the previous version of rails 4.2.11 and devise 3.4.0, generate_confirmation_token! was storing 64 char confirmation_token in the user record while signup and it is validating the confirmation_token of user using Devise.token_generator.digest(User, :confirmation_token, original_token) while confirming the email.
Thank you!