UserStore migration and activation
Existing UserStore IDP instances do not adopt hardened semantics automatically. ProAuth expands the schema first, then lets an administrator preview, backfill, remediate conflicts, verify deployment readiness, and activate the new behavior explicitly.
Why activation is explicit
Several changes are unsafe in a mixed-version fleet. An older node cannot reliably interpret new invitation, identifier, contact, abuse-control, identity, or revocation state. Silent startup activation could therefore make behavior depend on which node receives a request.
The migration workflow separates safe schema deployment from the irreversible compatibility boundary. The administrator attests that every serving node runs the coordinated release and that the inventory has not changed since preview.
Hardening modes and metadata
These UserStore IDP-instance options are written by the migration workflow. They are locked in the generic option editor.
| Option | Values | Default | Meaning |
|---|---|---|---|
UserStoreHardeningMode | Legacy, Hardened | Legacy | Records completion of the coordinated migration. Only the activation API changes it to Hardened; it is not a general-purpose switch for individual v2 workflows. |
UserStoreHardeningActivationFingerprint | SHA-256 fingerprint | empty | Exact completed inventory recorded at activation. Read-only provenance. |
UserStoreHardeningActivatedOn | UTC ISO 8601 timestamp | empty | Activation time. Read-only provenance. |
UserStoreHardeningAllNodesCurrentAttested | Boolean | false | Records the explicit fleet attestation. Read-only provenance. |
Hardening activation also sets AbusePolicyMode=Layered. It does not silently choose a typed password recommendation; use the separate password-policy preview and apply workflow.
Password-policy activation has its own locked provenance options:
| Option | Meaning |
|---|---|
PasswordPolicyActivationFingerprint | Exact recommendation preview recorded when it was applied. |
PasswordPolicyActivatedOn | UTC time at which the recommendation was applied. |
PasswordPolicyAllNodesCurrentAttested | Administrator's all-serving-nodes-current attestation. |
Retention options introduced with hardening
| Option | Valid values | Default | Guidance |
|---|---|---|---|
UserDeletionQuarantineDays | 0–365 | 30 | Time during which a deletion can remain quarantined before irreversible erasure. Use 0 only when immediate erasure is legally and operationally appropriate. |
UserTombstoneRetentionDays | 30–3650 | 365 | Reserved retention metadata for the non-authenticating subject tombstone. The current release does not run an automatic tombstone-purge job from this value; do not rely on it as an active deletion schedule. |
These values do not override legal hold. A tombstone is not an account and cannot authenticate or restore credentials.
Phase 1: expand and deploy
- Back up the ProAuth and every UserStore database.
- Apply the SQL Server or PostgreSQL migrations using the database deployment job.
- Deploy the same coordinated image version to ProAuth, background workers, AdminApp, and all other serving components.
- Confirm that no pre-hardening pod, job, or rollback ReplicaSet can receive traffic.
- Verify state-store, pub/sub, Data Protection, and notification-outbox health.
At this point, existing instances remain in compatibility mode. Startup does not rewrite credentials, invalidate reset artifacts, cancel invitations, or activate layered abuse policy.
Phase 2: preview the inventory
GET /api/management/v2/idpinstances/{idpInstanceId}/userstore-hardening-migrationThe response contains:
| Field | Meaning |
|---|---|
TotalUsers | UserStore users included in the inventory. |
UsersMissingCanonicalIdentifiers | Users whose current canonical login name or email has not been backfilled. |
QuarantinedIdentifierConflicts | Users involved in an ambiguous canonical login-name conflict. |
ConfirmedEmailsMissingUnifiedContact | Confirmed legacy emails not yet represented as active verified contacts. |
LegacyPasswordResetArtifacts | Version 0 reset artifacts that must be invalidated. |
BackfillComplete | true only when all prerequisites are clear. |
Fingerprint | SHA-256 fingerprint of the exact inventory and security-contact state. |
Store the fingerprint with the change record. It is an optimistic-concurrency boundary, not a secret.
Phase 3: run bounded backfill
POST /api/management/v2/idpinstances/{idpInstanceId}/userstore-hardening-migration/batches
Content-Type: application/json{
"batchSize": 250,
"allServingNodesCurrentAttestation": true
}BatchSize must be 1–500. Each batch is idempotent and:
- writes versioned canonical login-name and email values;
- quarantines duplicate canonical login names;
- creates verified contacts for confirmed legacy emails with
LegacyConfirmedBackfillprovenance; - invalidates plaintext or version 0 password-reset artifacts;
- records the administrative actor on changed UserStore rows.
Run batches until no eligible work remains. The AdminApp User Store → Migrations → Store hardening view uses a batch size of 250.
Backfill changes security state
The all-nodes-current attestation is required before the first backfill write, not only at final activation. A confirmed legacy email becomes a purpose-bound verified contact, while old reset artifacts stop working.
Resolve canonical identifier conflicts
ProAuth never chooses a winner when two display values canonicalize to the same login name. Both remain quarantined from ambiguous identifier flows.
For each conflict:
- identify the correct people through an authoritative administrative process;
- choose distinct login names according to the customer's naming policy;
- update the affected users through UserStore API v2 with normal concurrency controls;
- rerun a backfill batch;
- confirm that
QuarantinedIdentifierConflictsandUsersMissingCanonicalIdentifiersreach zero.
Do not resolve a conflict by changing database collation or editing canonical columns directly.
Migrate legacy invitations
Inventory legacy invitation identity markers before hardening activation:
GET /api/management/v2/unified-invitations/legacy-migration?subscriptionId=<subscription-id>&tenantId=<optional-tenant-id>The inventory has its own deterministic fingerprint. Reissue one marker with:
POST /api/management/v2/unified-invitations/legacy-migration/reissues
Content-Type: application/jsonThe command requires the subscription, ProAuth user, legacy identity row, tenant, target client, exact eligible IDP list, LifetimeHours (1–2160), invitation policy fingerprint, preview fingerprint, and RequiredApprovals (0–5).
Reissue first verifies the unchanged inventory, invalidates the old marker, creates a unified invitation, and queues durable delivery. The legacy identity ID is a uniqueness key, so repeating the same successful request returns the existing invitation rather than creating another.
The AdminApp migration view exposes this as Cancel and reissue. A cancelled legacy marker is never restored during rollback.
Phase 4: verify deployment readiness
Before activation:
- Confirm that all serving nodes and background workers run the same supported ProAuth version and that database migrations completed successfully.
- Use shared state and messaging services for multi-instance deployments. In-memory state is suitable only for a single serving instance.
- Verify sign-in, invitation delivery, configured recovery routes and administrator access in your staging deployment with representative accounts.
- Review the backfill results, resolve identifier conflicts, and confirm that the rollback restrictions are understood by the deployment owner.
Phase 5: activate
Refresh the inventory immediately before activation, then call:
POST /api/management/v2/idpinstances/{idpInstanceId}/userstore-hardening-migration/activate
Content-Type: application/json{
"previewFingerprint": "<current-fingerprint>",
"allServingNodesCurrentAttestation": true,
"impactAcknowledgement": "Approved change CHG-12345; pre-hardening rollback is prohibited"
}Activation succeeds only when backfill is complete, no canonical conflicts remain, the fingerprint still matches, the fleet attestation is true, and the impact acknowledgement is non-empty. Legacy invitation inventory is a separate subscription-scoped prerequisite; the activation endpoint does not infer or drain it for you.
The result records the IDP instance, fingerprint, activation time, Hardened mode, and Layered abuse mode.
Rollback boundaries
| Point | Supported rollback |
|---|---|
| Before backfill | Roll back the application after normal schema-compatibility review. |
| After backfill but before activation | Remain on the coordinated release, correct data, and complete or defer activation. Do not restore invalidated reset artifacts. |
| After activation | Do not run a pre-hardening binary. Future option values may be changed within supported validation, but irreversible state is not undone. |
The following never roll back automatically:
- password hashes already rehashed to the new envelope;
- authentication-security epochs and revocation cutoffs;
- cancelled or superseded invitations;
- completed identity replacements;
- resolved canonical identifiers after their uniqueness boundary is active;
- erased users and tombstones.
Post-activation monitoring
Monitor at least:
- invitation expiry, replay, proof failure, assignment failure, and approval age;
- layered abuse decisions by dimension and operation;
- security-contact verification and replacement failure;
- identity-replacement proof, expiry, and cleanup status;
- stale epoch and scoped-cutoff rejection;
- outbox age, retry count, and dead letters;
- state-store CAS contention and provider availability;
- deletion quarantine, erasure, and tombstone backlog.
Treat any unexpected return to Legacy, fingerprint drift, or serving-node version drift as an incident.