In a customer-support system, the hard part of account shutdown is deciding what must stop now and what can wait. A stolen refresh token is an immediate abuse problem; an account deletion request is a data-lifecycle problem with a different recovery window.
Short answer: keep a stable user ID, mark profile state before destructive work, revoke every session for a compromise, and delete only after the recovery and audit requirements are satisfied. Profile state and session revocation are complementary controls, not competing implementations.
The incident lesson: shutdown is two clocks, not one
The bounded production scenario is familiar: a support agent reports that a customer session was copied from a browser. The bot is already trying refresh requests, while the customer also asks to close the account. Treating both requests as “delete the user” creates a race: the attacker may retain a valid session until deletion finishes, and a hurried delete can remove the information needed to investigate the event.
The invariant is simple. Identity stability comes first. Use the user ID as the primary key; an email address is a lookup aid and can change. Record the state transition in the business layer, restrict who may make a high-privilege transition, then handle session and storage consequences as separate operations. I initially expected one destructive endpoint to simplify the runbook. It made the safety boundary harder to explain, because a support operator, a fraud reviewer, and a deletion worker each have different authority and different evidence to retain. A queue retry, a stale cache entry, and a second browser can all arrive between those decisions, so the runbook has to name the order rather than imply it.








