Join our Newsletter — 33% off our NHI Course
Home› Guides› CIAM User Migration Guide: Moving Customers Without Forcing…
Guide Customer Identity

CIAM User Migration Guide: Moving Customers Without Forcing Password Resets

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 13 November 2026 14 min read
On this page

A customer identity migration that forces every user to reset their password loses customers, floods the help desk and gives phishers a perfect pretext. Moving millions of customer accounts from a home-grown login, a legacy identity provider or an acquired company's user store into a new CIAM platform can be done without mass resets, using bulk import of existing password hashes, lazy (just-in-time) migration at sign-in, or a mix of both. This guide explains the three patterns, how to choose between them, how to handle legacy hash formats safely, and how four widely used platforms document each step. It is written for identity architects, application security engineers and product owners planning a customer identity cut-over. Platforms are listed alphabetically, and the order is not a ranking. For the specific Azure AD B2C retirement path, see the Azure AD B2C to Entra External ID guide.

Key takeaways

  • Three patterns, one goal. Bulk hash import moves everyone at once, lazy migration moves users as they sign in, and a staged reset is the fallback for accounts that cannot be moved any other way.
  • Your hash format decides the options. Modern hashes (bcrypt, scrypt, Argon2id, PBKDF2) can often be imported directly; unsalted or legacy hashes usually need lazy migration so the password is re-hashed at the next sign-in.
  • Lazy migration keeps the old system alive. The legacy store must stay available, patched and protected against brute force until the long tail of users has moved or been retired.
  • Migration is a security upgrade opportunity. At the moment a plaintext password is seen at sign-in, check it against breached-password lists and prompt for a passkey or MFA.
  • Plan the end before the start. Decide when unmigrated accounts get a staged reset or are deleted, and how the legacy validation path is switched off.

The three migration patterns

PatternHow it worksUser experienceMain risksBest fit
Bulk import with password hashesExport users and hashes, transform to the target schema, import through the platform's bulk import job or APIInvisible: users sign in with their existing passwordHash export handling; unsupported algorithms; weak legacy hashes carried over unchangedSource uses a modern, supported hash; you want a single cut-over date
Lazy (just-in-time) migrationOn first sign-in to the new platform, a script, hook or function validates the password against the legacy system, then the platform stores its own hashInvisible for active usersLegacy system must stay online; validation endpoint becomes a brute-force target; long tail of inactive usersUnsupported or weak hash formats; source only validates passwords and cannot export hashes
Staged resetImport profiles without credentials; users set a password or enrol a passkey through an activation or reset emailVisible: every user must actDrop-off, support load, phishing lookalikes of the reset emailSmall user bases, accounts with no usable credential, or the clean-up phase after lazy migration

Most large programmes combine them: bulk import for profiles (and hashes where supported), lazy migration for credentials that cannot be imported, and a staged reset or deletion for the inactive tail.

Choosing a pattern

  • Can you export hashes at all? Some identity providers may not offer a password hash export. If not, lazy migration against the provider's sign-in endpoint, or a staged reset, are the only options.
  • Is the algorithm supported by the target? Check the target's documented algorithm list and parameter limits before designing the transform. If one part of the user base uses a different scheme (for example after an earlier acquisition), split it into separate import jobs or route it to lazy migration.
  • Is the legacy hash strong enough to keep? Unsalted MD5 or SHA-1 hashes should not be carried into the new platform as-is. Lazy migration replaces them with the target's own hash at the next sign-in.
  • How long can the source stay up? Lazy migration typically runs for months because inactive users sign in rarely. If the source must be decommissioned by a fixed date (a contract end, an acquisition integration deadline), bulk import is the safer core.
  • Size of the organisation: a small B2C service with tens of thousands of users can often accept a well-communicated staged reset with passkey enrolment. Large consumer brands with millions of accounts should avoid it except for the inactive tail.

For the wider platform decision see the Customer IAM (CIAM) Guide and the Customer identity (CIAM) platform rollout playbook.

Password hashes: formats, strength and safe handling

Every hash import starts with identifying exactly what the source stores: the algorithm, the cost parameters, the salt and where it sits relative to the password, any pepper (a secret added before hashing), and the encoding. A bcrypt string such as one beginning $2b$10$ carries its algorithm, cost and salt inside it; older schemes often store salt in a separate column. A pepper held in the old application's configuration cannot be reproduced by most targets, which usually forces lazy migration.

Source hashOWASP Password Storage Cheat Sheet positionMigration approach
Argon2idPreferred; minimum m=19456 (19 MiB), t=2, p=1Import where the target accepts it; otherwise lazy migration
scryptWhen Argon2id is unavailable; N=2^17, r=8, p=1Import where supported, checking parameter limits
bcryptLegacy systems; work factor at least 10; 72-byte password limitImport is widely supported; plan to rehash if the cost is below 10
PBKDF2-HMAC-SHA256For FIPS-140 needs; 600,000 iterations recommendedImport where supported; rehash if iterations are far below current guidance
Salted SHA-1, SHA-256 or SHA-512 (single pass)Not a password hashing functionLazy migration so the target creates its own hash at sign-in; reset the inactive tail
Unsalted MD5 or SHA-1, or reversible encryptionNot acceptable for storageLazy migration or staged reset; never import as the long-term credential

OWASP describes two ways to upgrade weak hashes: rehash at the next login and expire long-inactive accounts, or wrap the old hash inside a stronger algorithm as an interim step, replacing it with a direct hash at the next login. Store the algorithm and cost with every hash (for example in PHC string format) so old and new can coexist during the transition. OWASP ASVS 5.0 requirement V11.4.2 asks for passwords to be stored with an approved, computationally intensive key derivation function. See the Password Hashing and Key Derivation Guide.

Handling the export

  • Treat the export as a credential dump: hash files are exactly what attackers crack offline. Encrypt them at rest and in transit, keep them out of tickets, chat and shared drives, and delete them once each import job is confirmed.
  • Least privilege for migration identities: the scripts and service accounts that read the source and call the target's import API hold very powerful machine credentials. Scope them to the migration, store them in a secrets manager and revoke them at the end.
  • Test with synthetic data first: Okta's bulk migration guidance recommends testing with non-real data in progressively larger batches before production.

Platform how-to: Amazon Cognito

  • Bulk import with hashes: the CSV user import job accepts a password_hash column when the job is created with a hashing algorithm: BCRYPT, SCRYPT, ARGON2ID or PBKDF2_SHA256. All hashes in one job must use the same algorithm, and imported users are created as CONFIRMED. Without hashes, imported users are in RESET_REQUIRED.
  • Lazy migration: the Migrate user Lambda trigger runs only when the user does not yet exist in the pool, with trigger sources UserMigration_Authentication and UserMigration_ForgotPassword. Set finalUserStatus to CONFIRMED to keep the existing password (RESET_REQUIRED is the default) and messageAction to SUPPRESS to skip the welcome message. Return every attribute the pool marks as required.
  • Flow and policy notes: the trigger runs for USER_PASSWORD_AUTH, ADMIN_USER_PASSWORD_AUTH and USER_AUTH with a password, and imported-hash users use those flows until their first sign-in; SRP becomes available afterwards. AWS documents that password policy checks for migrated and imported passwords are the customer's to apply: validate strength in your function and set RESET_REQUIRED where a password fails.
  • Limits: 100 MB and 500,000 users per CSV file, one active import job at a time, and a CloudWatch Logs role for the job.

See the Amazon Cognito Security Guide.

Platform how-to: Auth0

  • Bulk import with hashes: POST /api/v2/jobs/users-imports into a database connection, with each user's hash supplied in custom_password_hash using an algorithm listed in Auth0's user import schema. Users whose hashes use an unsupported algorithm must reset their password on first login. Track jobs with GET /jobs/{id} and GET /jobs/{id}/errors.
  • Lazy migration: create a custom database connection to the legacy store and turn on Import Users to Auth0. When a user not yet in Auth0 signs in, the login() script validates against the legacy store and Auth0 creates the user with the same ID and password; getUser() supports sign-up and password change flows.
  • Finishing: confirm all users exist in Auth0, replace both scripts with no-op functions that return callback(null, null), and keep Import Users to Auth0 turned on. Auth0 recommends marking users as migrated in the legacy store so intentionally deleted users are not recreated.
  • Limits: 500 KB per import file, two concurrent import jobs per tenant, a two-hour job timeout, and upsert off by default; upserts overwrite rather than merge metadata.

See the Auth0 Hardening Guide.

Platform how-to: Microsoft Entra External ID

  • Bulk profile migration: create accounts through Microsoft Graph as local accounts. Set the password directly where plaintext is available; otherwise set a unique, strong random password and a directory extension property (for example toBeMigrated) to track credential migration.
  • Lazy migration: for applications already signing in through External ID, the OnPasswordSubmit custom authentication extension validates the submitted password against the legacy identity provider, writes it to the External ID account and clears the migration flag. Later sign-ins authenticate directly.
  • Legacy-initiated harvesting: where applications still call the legacy provider, it can validate the password and write it to External ID during the transition, then applications move over and the legacy provider is retired. Users not migrated by then reset their password at first sign-in.
  • Limits and safeguards: Microsoft notes Graph throttling at large volumes and advises protecting the migration REST API against brute force with a failed-attempt threshold. It also recommends migrating only needed attributes, merging duplicates and skipping stale accounts.

See the Azure AD B2C to Entra External ID guide.

Platform how-to: Okta

  • Bulk import with hashes: create users through the Users API with an imported hashed password and activate=true. The hash object takes algorithm, workFactor, salt and value; Okta's bulk migration sample uses BCRYPT with workFactor 10, and the Create User API reference lists the accepted algorithms.
  • Lazy migration: create users with a password hook of type default. At first sign-in the password import inline hook sends the submitted credentials to your service; returning the command com.okta.action.update with credential VERIFIED imports the password into Okta, and later sign-ins do not call the hook. An empty 204 response rejects the sign-in.
  • Staged reset: create users with activate=false so they receive an activation email and set a new password.
  • Limits: API rate limits depend on the service level purchased; Okta advises monitoring rate-limit headers and working with Okta Support to schedule large migrations. The import token needs the okta.users.manage scope.

See the Okta Security Hardening Guide.

Implementation: a phased migration

  1. Discover: profile the source: user count, active versus inactive (last sign-in), hash algorithms and parameters, duplicate and unverified email addresses, social and federated accounts, and MFA enrolments.
  2. Clean and map: merge duplicates, decide which stale accounts not to migrate, map attributes to the target schema and keep stable user identifiers so downstream systems and tokens still match.
  3. Pilot with synthetic users: run imports and lazy flows against test data; verify sign-in, password reset, MFA and account linking.
  4. Migrate profiles and supported hashes: run bulk jobs in batches within rate limits, reconcile counts and errors per batch, and securely delete each export once confirmed.
  5. Switch sign-in to the new platform with lazy migration on: route a small percentage of traffic first where your architecture allows, watch success and error rates, then move all traffic.
  6. Upgrade credentials in flight: on each lazy migration, check the password against a breached-password list, require a reset where it is compromised or fails policy, and offer passkey or MFA enrolment.
  7. Close the tail: after a set period, send a staged reset to remaining active accounts, delete accounts past your retention rule, and switch off the legacy validation path (no-op scripts, removed hooks or disabled functions).
  8. Rollback plan: keep the legacy store read-write and authoritative until cut-over is confirmed, so traffic can be routed back. Accounts created or changed in the new platform during the window must be synchronised back or reconciled.

Detection and measurement

  • Migration coverage: percentage of active users migrated per week, and the size of the unmigrated tail by last sign-in date.
  • Sign-in success rate: compare first-attempt success on the new platform with the legacy baseline; a drop points to hash transform or attribute mapping errors.
  • Forced resets: number and rate of users pushed to reset, split by reason (unsupported hash, breached password, policy failure).
  • Legacy validation abuse: failed validations per source IP and per account on the lazy migration endpoint, alerting on bursts typical of credential stuffing (MITRE ATT&CK T1110.004).
  • Support contacts: help desk tickets about sign-in per thousand active users, compared with the pre-migration baseline.
  • Credential upgrade: share of migrated users who enrolled a passkey or MFA during migration.

Common failure patterns

  • Carrying weak hashes forward: unsalted or fast hashes are imported as the permanent credential, so the new platform inherits the old platform's cracking risk.
  • Unprotected validation endpoint: the lazy migration API that checks passwords against the legacy store has no rate limiting, turning it into a credential-stuffing oracle. The 23andMe credential stuffing breach shows how reused passwords and weak detection on customer sign-in combine; the same controls (rate limits, burst detection, breached-password checks) belong on the migration path.
  • Hash exports left behind: CSV or JSON files containing hashes stay in storage buckets, laptops or tickets long after the import.
  • Identifier drift: new user IDs break links to orders, consents and downstream systems, or create duplicate accounts when email addresses differ in case or format.
  • A legacy system that never dies: lazy migration has no end date, so the old login stack stays exposed and unpatched for years.
  • Mass reset by default: a reset email to every customer trains users to click password emails and is quickly imitated by phishers. See the Credential Stuffing Attack Response Playbook for the response side.

Framework mapping

FrameworkReferenceRelevance to migration
OWASP ASVS 5.0V11.4.2Passwords stored with an approved, computationally intensive key derivation function
OWASP ASVS 5.0V6.2.12, V6.3.1Breached-password checks; credential stuffing and brute-force controls on the migration path
OWASP ASVS 5.0V6.4.1, V6.4.3Secure initial passwords and activation codes for staged resets; reset must not bypass MFA
NIST SP 800-53 Rev 5IA-5, IA-5(1)Authenticator management and password-based authentication
NIST CSF 2.0PR.AA-01, PR.AA-03, PR.DS-01Credentials managed, users authenticated, hash exports protected at rest
MITRE ATT&CKT1110.004, T1078Credential stuffing against the validation path; valid account abuse after migration

Practitioner checklist

  • Profile the source: user counts, last sign-in, hash algorithms and parameters, peppers, duplicates.
  • Choose bulk import, lazy migration or staged reset per user segment, and document why.
  • Confirm the target's supported algorithms and parameter limits before writing the transform.
  • Encrypt hash exports, restrict access to named people and delete them once each job is confirmed.
  • Scope and vault the migration service credentials, and revoke them at the end.
  • Rate-limit and monitor the lazy migration validation path.
  • Check passwords against breached lists during lazy migration and offer passkeys or MFA.
  • Keep user identifiers stable and reconcile counts after every batch.
  • Set an end date for lazy migration, then stage resets or delete the remaining tail.
  • Switch off and decommission the legacy validation path and store.

Standards and references

Related NHI Mgmt Group resources: Customer IAM (CIAM) Guide · Password Hashing and Key Derivation Guide · Breached password checks · Passkey Rollout Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 13 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org