DEV Community

PrestonCole1111
PrestonCole1111

Posted on

Authenticated Password Change — Reverification and Existing-Session Policy for Support

A support portal has a different failure mode from a toy login form: an authenticated password change may happen while an agent is helping a customer and an attacker is trying to keep an existing-session alive. The operational constraint is continuity under suspicion.

Short answer: require recent, independent reverification before an authenticated password change, then revoke every session except the one that completed the change unless your incident policy explicitly requires a full logout. Tell the user what happened and make recovery predictable.

The dangerous moment is an already-authenticated browser

A password form often trusts the same session that is being protected. That is backwards. A cookie proves possession of a browser credential; it does not prove that the person at the keyboard still controls the account's email or another enrolled factor. OWASP recommends reauthentication for sensitive actions and checking the current password before allowing a change.

For a customer-support account, ask for the current password and a fresh factor challenge. The challenge should be bound to the account, expire quickly, and be single-use. Do not reveal whether the email address exists while sending recovery mail; the response should look the same for known and unknown addresses. Rate-limit attempts by account, source, and challenge, with a review path for a legitimate agent behind a shared NAT.

I once treated a successful password POST as the end of the flow. It was not. The next request still carried a 30-day refresh token, so changing the password changed almost nothing for a stolen laptop. That bug was a policy mistake, not a hashing mistake.

How should reverification and existing-session policy work together?

Model the change as a state transition, not a single endpoint. Start with an authenticated session, step up to a fresh proof, verify the current password, validate the new password against a breached-password blocklist, and only then write the new password hash. Generate an event with the actor, account, timestamp, source metadata, and result. Never put passwords or one-time codes in that event.

The session decision belongs in the same transaction boundary as the password update. A useful default is: rotate the session that made the change, revoke all other refresh tokens, and require those browsers to sign in again. Keep a short grace period only for a documented support workflow, and mark that session as recently reverified.

def change_password(ctx, current_password, new_password, factor_code):
    account = ctx.account
    require_authenticated(ctx.session)
    require_recent_reverification(ctx.session, max_age_seconds=300)
    require_factor(account, factor_code)
    if not verify_password(current_password, account.password_hash):
        raise AuthError("password change denied")
    validate_password_policy(new_password)
    account.password_hash = hash_password(new_password)
    revoke_refresh_tokens(account.id, except_session=ctx.session.id)
    rotate_session(ctx.session)
    record_security_event("password_changed", account.id, ctx.request_metadata)
    send_security_notice(account.email)
Enter fullscreen mode Exit fullscreen mode

The exact five-minute value is a policy choice, not a universal standard. Your mileage may vary when agents use long-lived desktop sessions, but the choice should be explicit and tested. Don't hide it in a library default.

Small details matter.

Migration checks and rollout trade-offs

Moving off a managed identity service is where these rules usually get lost. Inventory every credential: browser cookies, refresh tokens, mobile tokens, API keys used by support tooling, and password-reset links. For each class, write down its issuer, storage location, maximum lifetime, revocation mechanism, and the exact event that invalidates it; this list often exposes a forgotten browser cookie or a help-desk script with a year-long token. Decide which can be revoked centrally and which must expire naturally. A migration that copies password hashes but leaves old refresh tokens valid has preserved the most valuable foothold. Revoke them.

Run contract tests against both systems. Change a password in one environment, replay an old refresh token, submit a second factor code twice, and retry the request after the reverification window closes. Assert the same denial shape for wrong current passwords and unknown accounts where enumeration resistance matters. Add an alert for a password change followed by a burst of failed sign-ins; that sequence deserves investigation even when each individual request is valid.

Policy choice Helps with Cost or boundary
Revoke every other session Limits damage from a stolen browser Interrupts active support work; provide a clear sign-in path
Keep the changing session only Preserves the current task Unsafe if that browser is the compromised one
Require a second factor every time Strong defense for privileged agents Adds delivery and accessibility friction
Trust recent login for a short window Fewer prompts during routine work A stolen fresh session remains useful during that window

The catch is that there is no session rule that fits every support organization. Full revocation is not suitable when an account represents a shared on-call identity with no reliable handoff; use named accounts and a stronger factor instead. Stick with a short reauthentication window when agents handle billing or identity data. If your team cannot explain how a user regains access after losing a factor, the policy is not ready to ship.

Start in shadow mode, measure prompts, delivery failures, and revoked-token replays, then enforce for a small group of support agents. Keep the old provider available only for a bounded rollback period, and document exactly which sessions survive each step.

References

Top comments (0)