When you’re migrating from a custom authentication solution to Devise, it’s highly likely your users’ passwords are hashed or stored differently from how Devise does it.
If the legacy system has a sane, secure solution then you can implement a custom encryptor for Devise. However if that’s not the case or if you want to migrate to the Devise default way-of-life following convention over configuration and reducing maintenance headaches in the future, you should convert the passwords so that Devise can use them.
Since hopefully you stored hashes of your user’s passwords instead of encrypted or plaintext, the only moment you can retrieve the plaintext password for rehashing is when the user tries to log in. At that point we’ll convert it to Devise. This way when a user logs in his legacy password will be automatically converted to the new system.
First, add the legacy_password boolean attribute to User. This is to mark the passwords that have already been converted. Make sure to set it to true for the existing (legacy) records.
<pre lang=”bash”>$ rails g migration AddLegacyPasswordToUser legacy_password:boolean
$ rake db:migrate</pre>
Devise creates the method User#valid_password? to check the password. Let’s override it and add our legacy password check or fall through to the default valid_password? if the password was already converted. This code assumes the old password is stored in the same field as the converted password — encrypted_password.
class User < ActiveRecord::Base
# Use Devise’s secure_compare to avoid timing attacks
if Devise.secure_compare(self.encrypted_password, User.legacy_password(password))
self.password = password self.password_confirmation = password self.legacy_password = false self.save! else return false end end super(password) end
# Put your legacy password hashing method here
Supporting two different systems like this could soon become a maintenance nightmare After a couple of months, when the most active users have logged in at least once and converted their passwords, you can easily remove the extra code. Legacy users will be forced to reset their password since it won’t match anymore. Using the legacy_user attribute you could send them a targeted mail or alert them of the fact that they won’t be able to log in anymore with their old password.