DEV Community

CelesteRaine1783
CelesteRaine1783

Posted on

Progressive Profiling for Property Login Risk: Updating a Verified User (4 Rules)

Short answer: progressive profiling updates a verified user by keeping the subject ID immutable, binding every late profile field to that subject, and letting device risk change the required proof for the session rather than create another identity. For a property-management portal, a tenant can add an emergency contact after verification while the original evidence, lease links, and consent history remain attached to one record.

That boundary is the architecture decision. Identity is durable evidence; profile data is a mutable claim; a session is a temporary authorization decision. I write those as separate concepts because a profile form is an attractive place to accidentally smuggle in an account-creation flow.

The invariants and failure boundaries

A verified user receives one opaque subject identifier. It must not be an email address, lease number, or device fingerprint. The profile store may change a phone number or preferred language, but it cannot mint a second subject because the field arrived late. Verification evidence gets its own append-only record with issuer, time, method, and a reference to the subject.

Device fingerprints are signals, not proof. Store a keyed or salted representation, collection time, and a reason code; keep raw material on a bounded retention schedule. A browser update, privacy setting, or corporate proxy can change the signal without changing the person. A replacement phone is ordinary tenant behavior.

My four invariants are:

  1. The subject ID never changes after verification.
  2. A profile patch requires an authenticated session and field-level authorization.
  3. Risk may require stronger authentication, but it cannot silently lower assurance.
  4. Each accepted or rejected patch is attributable and replay-safe.

The failure boundary follows from those rules. A duplicate email, stale session, or unfamiliar device is a reason to challenge the request, not a reason to create identity number two.

Keep it boring.

How can progressive profiling update a verified user without recreating identity?

The write path is intentionally narrow. The client submits a patch and an idempotency key; the server resolves the session to its subject; policy checks the fields and assurance age; a transaction writes the profile and an audit event. Profile reads and profile writes are separate permissions.

def patch_profile(request, session, profile_store, audit_log, risk_engine):
    subject_id = session.require_subject()
    session.require_recent_auth(max_age_seconds=300)

    patch = request.json()
    writable = {"phone", "emergency_contact", "preferred_language"}
    unknown = set(patch) - writable
    if unknown:
        raise ValueError("profile field is not writable")

    decision = risk_engine.score(
        subject_id=subject_id,
        device_fingerprint=request.device_fingerprint,
        action="profile_update",
    )
    if decision.requires_step_up:
        return {"status": "step_up_required", "reason": decision.reason}

    with profile_store.transaction() as tx:
        current = tx.lock_profile(subject_id)
        updated = tx.apply_patch(
            current, patch, idempotency_key=request.idempotency_key
        )
        tx.save_profile(updated)
        audit_log.append(
            tx=tx,
            subject_id=subject_id,
            event="profile_updated",
            changed_fields=sorted(patch),
            device_signal=decision.reason,
        )
    return {"status": "updated", "subject_id": subject_id}
Enter fullscreen mode Exit fullscreen mode

The order matters. If the handler accepts a client-supplied user ID, an altered parameter can redirect a valid session to another tenant. If it writes the profile before checking assurance, a stolen but still-live cookie can change a recovery phone. If it commits the row and emits the audit event separately, incident response gets an incomplete story. Consider a tenant who signs in from a shared lobby tablet, starts a profile update, then finishes it from a phone after the browser is refreshed: the request may carry a new fingerprint, an old session timestamp, and a retried idempotency key. A correct implementation resolves the same subject, re-evaluates assurance, returns the prior result for the retry, and records the reason for any step-up. It does not infer a new person from a changed device signal, and it does not silently overwrite a recovery field merely because the second request arrived last.

I once treated a five-minute freshness limit as a universal answer. It wasn't. A language preference can tolerate a normal session, while a recovery factor or payout destination should trigger recent reauthentication, a one-time code, and a notification. Your mileage may vary; the right threshold follows the consequence of a wrong update and the support team that must handle it.

Which storage shape preserves identity while profiling grows?

Design Strength Cost or risk Suitable boundary
Subject and profile tables Simple joins and atomic patches Schema coordination for new fields One portal with a stable field set
Separate profile service Independent ownership and policy Cross-service consistency and retries Several products sharing identity
Event-sourced profile history Replayable, detailed history More complex reads and migrations Operations with strict audit needs

I usually begin with a subject table, a profile table, and an outbox row in the same database transaction. The outbox consumer can publish a change event after commit, so a remote risk or notification service does not sit on the login request's critical path. Move to a separate service when ownership, residency, or scaling demands it; the split is not free.

The rejected shortcut is “create a new verified user, then merge later.” Merges can break foreign keys, duplicate consent records, and attach a trusted device to the wrong subject during the interval between creation and reconciliation. It has one valid use: a planned migration in which both records are independently authenticated, every reference is remapped transactionally, and the user is told what changed. That is migration work, not progressive profiling.

What should teams test before changing session friction?

Exercise the policy matrix with fixtures for shared tablets, expired sessions, replayed idempotency keys, concurrent edits, and a fingerprint that changes between requests. Assert that a step-up response leaves the profile untouched. Test that two writes against the same version produce either a visible conflict or a documented field-specific merge; silent last-write-wins is a poor default for recovery data.

Observe step-up rate and support contacts per field, not only aggregate login success. Alert on repeated challenges, unresolved subject/version references, and audit events whose transaction ID cannot be found. Those signals expose friction and integrity failures before a quarterly review does.

There is a human trade-off here. Holding every unfamiliar device for manual review protects recovery data, but it can strand a tenant outside their apartment after replacing a phone. Allowing every patch immediately feels smooth, yet a stolen session can change the very factor used to recover it. Pick the point in between that your threat model and support hours can sustain.

Keep the verified subject, authorize each mutable claim, and require proof proportional to the action's impact. A property portal that follows that rule can add fields progressively without rewriting identity, while its logs still explain who changed what, under which assurance, and from which risk signal.

References

Top comments (0)