Migrating passwords

Release 0.3.0 · Reviewed 2026-09-09

Optional integration in 0.3.0

Install the published add_auth package through your Rails app’s Gemfile, then rehearse these changes in an isolated copy of the app. Enable only the capabilities you need. Review the release status and upgrade procedure first.

Preserve a supported legacy verifier until the account has a valid current Rails password.

Check the effective verifier

Start with the source inventory. The bounded adapter covers the tested Devise bcrypt profile, including an explicitly supplied legacy pepper. A custom verifier, unknown digest, multiple scopes or missing identifier remains a blocker until its own conversion is proved. Never copy peppers or hashes into logs, reports or support tickets.

Prepare and backfill

The reviewed add_auth:devise_accounts migration preserves encrypted_password and adds canonical password/identifier fields. The bounded converter works in primary-key order, locks each account, rechecks source state and keeps Devise authoritative. It does not send mail or create sessions.

For contributor rehearsals, the source repository includes examples/devise_backfill.rb and executable interruption/conflict coverage in spec/migration/backfill_checkpoint.rb. These are version-specific contributor tools, not a production deployment command. The operator supplies a reviewed manifest and a private checkpoint directory. Resume with the same source, configuration and target; reconcile a blocked batch before advancing.

Select exactly one verifier

In the reviewed destination User model, include AddAuth::Rails::PasswordAdoption after has_secure_password. Configure the tested legacy verifier explicitly:

Rubyconfig/initializers/add_auth.rb
require "add_auth/core/passwords/legacy_bcrypt"
AddAuth.configure do |config|
  config.legacy_password_verifier = AddAuth::Core::Passwords::LegacyBcrypt.new
end

For a verified peppered source, supply pepper: -> { Rails.application.credentials.fetch(:legacy_devise_pepper) } to that adapter. Keep the secret only while the retained legacy cohort needs it.

The credential profile chooses its verifier. A failed Rails password never falls back to an old Devise digest. A successful compatible login can rehash under the account lock; historically valid passwords outside Rails’ new-assignment byte contract remain on their explicit verifier until reset. New-password policy does not invalidate an otherwise valid historical password at login.

Fence old writers

The opt-in AddAuth::Rails::Migration::SourceBridge belongs after Devise in a reviewed source model. It projects source credential writes while Devise is authoritative and rejects security writes or Devise admission after that account switches. It cannot inventory or fix arbitrary host workers and bulk SQL; drain incompatible writers and map their behavior before activation.

Verify replacement and interruption

Use real source-generated hashes. Prove current password acceptance, wrong-password denial, normalization conflicts, concurrent password changes, restart after a committed batch and zero migration mail. Then reset a password: the new password must work and the old password, sessions and spent reset links must remain invalid after a fresh compatibility boot.

If the verifier is unsupported, preserve the account and require an independently authorized enrollment/recovery path. Never invent confirmation provenance. Continue with migration recovery.

Something unclear? Suggest a correction Release status

Search documentation

Type to find a guide.

Use Tab to move through results. Escape closes search.