Rehearse an AddAuth update with persisted sessions, pending mail and your customized pages before changing the deployed bundle.
This guide covers upgrades to 0.5.1 from the 0.2.1, 0.2.2, 0.3.0, 0.4.0 and 0.5.0 packages. Read the target release’s changelog and availability first. The 0.x API can change between releases; a successful installation alone does not verify an upgrade.
Keep a recoverable starting point
- Save the deployed Gemfile.lock, application revision, generated migrations and
config/add_auth-ejections.json. Back up the database using your normal protected backup process. - Keep the same authentication keys, digest adapters, RP ID, origins, cookie configuration and account policy during the package update. Changing them is a separate migration that can invalidate sessions, proofs or encrypted jobs.
- In a disposable host with synthetic accounts, establish an ordinary session, a revoked session, a passkey, a strict account, a pending email and a queued security notification. Retain one customized ejected page.
- Record which web and worker revisions will run together. Do not assume arbitrary old/new workers are compatible because they use Active Job.
Update the application bundle
In the Rails host’s Gemfile, select the published target version you reviewed. Then run:
bundle update add_auth --conservative
bundle exec ruby -e 'require "add_auth"; puts AddAuth::VERSION'
bin/rails db:migrate:statusRun only the generators named by that release’s instructions, inspect the generated changes, and apply reviewed migrations with bin/rails db:migrate. Existing AddAuth generators preserve host files and do not apply migrations themselves. Repeat generation and migration in the rehearsal to check that they remain safe.
Keep your existing configuration
From 0.5.0, follow the 0.5.1 upgrade steps below. From 0.4.0 or earlier, also complete the UUID-support upgrade steps. Ordinary integer installations do not need a key conversion.
Running bin/rails generate add_auth:install again preserves config/initializers/add_auth.rb; it does not refresh it from the new gem. Review the installed template and merge relevant changes while retaining host policy and enabled features. The configuration setup guide gives the comparison command and prerequisites for optional confirmation. Do not add 0.4.0-only options to a 0.3.0 host.
Upgrading to 0.4.0 retains required confirmation by default. Optional confirmation needs the additive provisioning receipt migration and a reviewed host-policy change. Preserve that receipt during rollback; an older confirmation implementation can repeat onboarding for accounts provisioned by the new profile. Use a compatible rollback build or stop affected confirmation intake.
Upgrade to 0.5.1 security hardening
Version 0.5.1 hardens account confirmation, password lockout, sign-out everywhere and rate limiting. Set gem "add_auth", "~> 0.5.1" in your host Gemfile. It adds no migrations or new settings. Release status lists each behavior change.
- Complete the starting-point rehearsal and update the bundle. From 0.5.0 there is no new AddAuth migration to apply. From an older package, also follow the UUID-support steps.
- If you ejected any of these files, merge the 0.5.1 changes using the per-file review and baseline procedure:
app/controllers/add_auth/accounts_controller.rbapp/controllers/add_auth/passkeys_controller.rbapp/views/add_auth/accounts/_proof.html.erbapp/views/add_auth/account_mailer/link.text.erb
- Review
passkeys.anonymous_limit. It now applies to each IPv4 address or IPv6 /64 per five minutes rather than to all anonymous requests together. A value sized for total traffic may be higher than one network needs; account for users who share an address. - Automatic password lockout no longer ends sessions or blocks passkey, email-link or provider sign-in. If a support procedure relied on it for that, use a manual lock, which is unchanged.
- Restart the matching web and worker processes, run
bin/rails add_auth:doctorand complete the checks below.
With synthetic accounts, confirm an account started through a sign-in provider with both choices and check that only “Confirm and keep” retains the link. Trigger an automatic lock and check that passkey and email-link sign-in still work and a password reset clears it. Start an address change, sign out everywhere, and check that the pending confirmation link no longer works. Repeat the affected pages with Turbo, JavaScript without Turbo and no JavaScript.
Rollback boundary: 0.5.1 does not change the schema, so the saved 0.5.0 bundle and its ejection baseline remain a compatible code rollback. Returning to it also restores the earlier behavior; prefer a forward correction.
Upgrade to 0.5.0 authentication storage
Version 0.5.0 adds UUID sessions and the shared Rails primary-key generator setting. Set gem "add_auth", "~> 0.5.1" in your host Gemfile, then follow the rehearsal below. A package update does not convert existing integer tables to UUIDs.
This package upgrade preserves existing IDs, passwords, sessions, passkeys and pending proofs. An integer app, including one with UUID users and integer sessions, does not need to convert its tables. For a new all-UUID app or a later table-generation choice, see UUID and integer primary keys.
Local package rehearsals from the published 0.2.1, 0.2.2, 0.3.0 and 0.4.0 archives pass on Rails 8.0 and 8.1. They retain integer IDs, active and revoked sessions, strict passkey policy, pending delivery and customized ejections across upgrade and compatible code rollback. This evidence does not establish an integer-to-UUID conversion or mixed-version workers.
- Complete the starting-point rehearsal, choose the published target in your Gemfile, and update the bundle. Keep your authentication secrets, account policy and primary-key types unchanged during this package upgrade.
- In a host that already has AddAuth hardened sessions enabled, run the session upgrade generator below. It preserves existing files and adds the missing
add_add_auth_session_cursor_indexmigration. Re-running other feature generators is not required merely to keep their existing IDs. Installing an optional feature for the first time remains a separate setup step. - Review the migration before applying it. It adds
index_add_auth_session_cursoronsessions(user_id, created_at, id); it does not rewrite IDs or recreate sessions. On a large PostgreSQL session table, plan index construction in your deployment window or adapt the pending migration to your reviewed concurrent-index procedure. - If you ejected controllers, merge the updated
app/controllers/add_auth/sessions_controller.rb. Its current-browser check delegates typed-ID handling to Core instead of parsing an integer. Follow the per-file review and baseline procedure; rerunning the generator alone preserves the old file. - Update any custom session-list or mobile client code to return
next_cursorunchanged asbefore. The new cursor is an opaque string. Do not applyto_i,parseIntor numeric JSON validation. Legacy numeric navigation is accepted only for integer session schemas. - Apply the reviewed migration, restart the matching web and worker processes, and run doctor plus the verification below.
bin/rails generate add_auth:session_upgrade
bin/rails db:migrate:status
# Review the generated migration and any ejected controller changes first.
bin/rails db:migrate
bin/rails add_auth:doctorThe session generator enables hardened sessions if they were disabled. Use the session-adoption procedure in that case instead of treating this as a configuration-neutral upgrade. Existing initializers remain intact.
In bin/rails console, confirm the new index exists:
Session.connection.indexes(:sessions).any? do |index|
index.name == "index_add_auth_session_cursor" &&
index.columns == %w[user_id created_at id]
end
# => trueVerify the actual primary-key types still match the pre-upgrade schema. Rehearse at least 52 active sessions, including the current browser: visit an older page, revoke another session, and sign out the current browser. An unrelated account must stay inaccessible and a revoked bearer must remain rejected. Repeat affected browser flows with Turbo, JavaScript without Turbo, and no JavaScript; test JSON pagination if mobile sessions are enabled. Also complete the persisted credential and delivery checks below.
Rollback boundary: an upgrade that retains integer sessions can keep the additive index while restoring its matching saved bundle, application revision and complete ejection baseline. Start session navigation from the first page after rollback; old code does not understand the new opaque cursors. Do not restore old authentication rows. Once an app creates or converts to UUID sessions, older gems that require integer sessions are not a compatible rollback target. Keep a UUID-capable build available or deploy a forward correction.
Review customized files
bin/rails add_auth:doctorDoctor compares each stored upstream baseline with the new gem template. Its diff describes the upstream change; it is not a diff of your private customization. Review the change against your host file and incorporate applicable fixes while retaining your layout, copy and routing choices.
After testing one reviewed file, remove only that file’s entry from the files object in config/add_auth-ejections.json. Run the matching generator:
bin/rails generate add_auth:viewsUse add_auth:controllers, add_auth:javascript or add_auth:mailer_views for those file types. The existing host file stays in place and the current upstream baseline is recorded. Review the manifest diff and run doctor again. Do not delete the entire manifest or use overwrite flags to silence an unreviewed warning.
Verify the persisted journeys
- Resume an existing ordinary session; verify that the revoked session remains denied.
- Sign in with the existing passkey. Check that the strict account still rejects password/email fallback and requires permitted proof for management.
- Deliver eligible pending mail through a worker running the new bundle. Confirm that GET remains inert, POST consumes the link once, and replay fails.
- Retry a pending notification and a duplicate completed delivery. Observe job outcomes without logging links, bearer cookies or ciphertext.
- Exercise the customized page, Turbo validation, JavaScript without Turbo and permitted no-JavaScript navigation. Run doctor and the deployment checks.
Deploy and roll back deliberately
Apply additive migrations before switching readers and workers. If the release does not establish mixed-version job compatibility, pause new intake, drain or stop old workers, deploy the matching web/worker bundle and resume processing. Watch unavailable responses, failed jobs, pending-mail age and maintenance heartbeats.
The 0.2.1/0.2.2-to-0.3.0 package rehearsals preserve the baseline authentication schema, keys and jobs with new optional integrations disabled. Returning to the matching saved bundle and ejection manifest keeps spent proofs and revoked sessions denied in that profile. Enabling account lifecycle, provider or mobile persistence creates a separate migration boundary: retain compatible credential and revocation readers during rollback, following the migration recovery guide. Do not infer that old code can safely read newly enabled state.
Restore the matching application revision and complete set of ejected files, including the manifest. Review removal of files introduced only by the newer version: an older gem cannot load a new controller that requires newer APIs, even if its routes are disabled. Boot the rollback build with eager loading enabled before deployment.
Keep current authentication records during code rollback. Restoring an old database snapshot can revive revoked sessions and spent proofs; it requires a separate incident recovery and revocation procedure. Do not return to the stock signed-ID session reader after adopting AddAuth bearer sessions. If the previous version cannot safely read new state, retain the compatible schema, stop affected entry points and deploy a correction.
Next, review the integration boundaries and symptom-based checks.