DEV Community

UlyssesDonovan1529
UlyssesDonovan1529

Posted on

Identity-Centered Account Recovery: Preserving Player Continuity Beyond Email Addresses

Short answer: preserve a gaming account around a stable, opaque subject ID; treat email as a replaceable contact claim; and require recovery evidence strong enough to restore the player without turning an abandoned inbox into a permanent master key.

The evaluation constraint matters as much as the data model. A recovery design passes only if a legitimate player can regain purchases and progress after losing an address, an attacker who controls that old address cannot take over the account, and a GDPR deletion request revokes every active session before personal data enters the deletion workflow. Optimizing only completion rate makes recovery weak. Optimizing only lockout resistance makes it punishing.

The tempting first design is users.email as a primary key plus a reset link. It's easy to ship from a notebook-sized prototype. It also couples identity, routing, login, and recovery to one mutable string. Once the player changes providers, loses a school address, or has an inbox compromised, every assumption lands on the same brittle field.

Keep those concerns separate.

How should identity-centered account recovery preserve continuity beyond email addresses?

Continuity belongs to a subject, not an address. Game progress, entitlements, sanctions, parental-consent state, linked platform identities, authenticators, and security events should refer to a random internal subject_id. An email claim refers to that subject and carries its own verification and lifecycle metadata. Replacing the claim then changes where messages go; it does not move the player's account or rewrite ownership across game services.

That model creates three distinct questions. Can the person satisfy an authenticator already bound to the subject? Can they prove control of a verified recovery channel? If neither is available, does the service have enough independent evidence for a manual, higher-friction review? A CAPTCHA or knowledge of a display name doesn't answer any of them. Neither does a purchase receipt by itself: receipts can be forwarded, shared, or exposed, so a review policy should combine evidence and rate-limit attempts rather than promote one artifact into a universal credential.

OWASP recommends that recovery should not reveal whether an account exists and should use consistent messages and timing. The public response can therefore say that instructions will be sent when the submitted information matches an eligible account, while internal systems perform lookup, abuse checks, and notification. Uniform words aren't enough — response latency, status codes, and side effects also need evaluation. A 200 body that is generic but returns in 40 ms for an unknown address and 600 ms for a known one still gives an attacker a useful signal.

Recovery also needs a clear assurance ceiling. It must not become an easier route around the account's normal authentication policy. OWASP calls for reauthentication after account recovery and other high-risk events; for a game account, that can mean limiting sensitive actions until a fresh authenticator is enrolled, notifying previously trusted channels, and invalidating outstanding recovery challenges. I'm not sure one evidence threshold can fit both a free throwaway profile and an account holding years of paid entitlements. The uncertainty is resolvable: classify account harm, measure false recovery and lockout rates by tier, and review the thresholds with fraud, support, privacy, and security teams.

Model recovery as a state transition, not an email reset

A useful identity record has replaceable edges around a durable center. The center owns authorization and continuity. Email addresses, passkeys, passwords, platform identities, and recovery codes are claims or authenticators with independent states such as pending, verified, revoked, or expired. Do not merge two subjects automatically because they present the same email; recycled corporate and education addresses make that shortcut dangerous. Likewise, changing an email must not silently change subject_id.

The recovery flow can then move through explicit states: challenge issued, evidence accepted, account recovery-locked, new authenticator enrolled, old sessions revoked, and recovery completed. Every transition should be idempotent and auditable. Store a digest of a single-use recovery token rather than the bearer token itself, bind it to a purpose and subject, give it a short expiry, and consume it atomically. Concurrent submissions must produce one winner. The loser gets the same safe result without reactivating an already consumed path.

Here is a deliberately small Python boundary. It leaves evidence scoring and storage behind interfaces because those rules are application-specific, but it makes the security order visible:

from dataclasses import dataclass
from datetime import datetime, timezone
from typing import Protocol


@dataclass(frozen=True)
class AcceptedRecovery:
    subject_id: str
    challenge_id: str
    accepted_at: datetime


class IdentityStore(Protocol):
    def consume_challenge(self, token: str) -> AcceptedRecovery: ...
    def bump_session_epoch(self, subject_id: str) -> int: ...
    def add_authenticator(self, subject_id: str, credential: bytes) -> None: ...
    def finish_recovery(self, subject_id: str, challenge_id: str) -> None: ...


def complete_recovery(
    store: IdentityStore,
    token: str,
    new_credential: bytes,
) -> int:
    accepted = store.consume_challenge(token)
    store.add_authenticator(accepted.subject_id, new_credential)
    new_epoch = store.bump_session_epoch(accepted.subject_id)
    store.finish_recovery(accepted.subject_id, accepted.challenge_id)
    return new_epoch
Enter fullscreen mode Exit fullscreen mode

consume_challenge must enforce single use, purpose, expiry, and the current recovery state in one transaction. bump_session_epoch gives session validators a cheap revocation boundary: a session carries the epoch at issuance, and validation rejects it after the subject's epoch advances. That is useful for first-party sessions. For OAuth access or refresh tokens issued to other components, use their defined revocation and logout mechanisms as well; RFC 7009 defines OAuth token revocation, while OpenID Connect Back-Channel Logout defines a server-to-server logout signal. One local integer cannot magically retract every independently issued credential.

This is the catch: epoch checks add a read or cache dependency to session validation. Fully self-contained tokens are fast precisely because a verifier can accept them without consulting current subject state. If immediate global revocation is a hard requirement, pure statelessness is not suitable. Use short token lifetimes plus a stateful epoch or denylist, define cache invalidation latency, and test the actual worst case rather than labeling revocation "instant."

How can account deletion close every active session?

GDPR erasure is a lifecycle workflow, not a DELETE statement. Article 17 establishes the right to erasure and also lists exceptions, so privacy counsel and data owners need to classify what is erased, anonymized, restricted, or retained under another lawful obligation. The identity service should orchestrate that policy; it should not guess it from an email address.

For a player-confirmed deletion, first require recent authentication appropriate to the risk and create an idempotent deletion operation tied to subject_id. Then block new login and recovery, revoke first-party sessions, revoke applicable delegated tokens, and publish a versioned deletion event to every service that stores subject-linked personal data. Progression, commerce, social, anti-cheat, telemetry, support, and backups may have different deletion mechanics, so each consumer needs an acknowledgment contract and a retry policy. The coordinator records completion without copying deleted payloads into its logs.

Order matters. If personal data disappears before session invalidation, a still-valid token may continue to call downstream services against a half-deleted subject. If recovery remains open, an old email link may recreate access while deletion is in flight. The account state should therefore become deletion_pending at the start, and both authentication and recovery should fail closed for that state. Expected 401 and 403 decisions belong in metrics, but logs should carry pseudonymous operation IDs rather than raw emails or recovery tokens.

A compact contract keeps teams aligned:

Invariant Verification
Email replacement never changes subject_id Property test across claim rotation
A recovery challenge succeeds at most once Concurrent redemption test
Recovery advances the session epoch Old-session rejection test
Deletion blocks login and recovery before fan-out State-machine integration test
Every deletion consumer acknowledges the same operation Reconciliation report
Logs contain no bearer token or raw recovery secret Structured-log policy test

Backups need an explicit policy too. Erasure from live systems does not justify quietly restoring deleted personal data during disaster recovery. Record tombstones or equivalent suppression state under the approved retention design, and rehearse restoration so replayed data is deleted again before the service returns to normal access. The exact retention schedule is a legal and operational decision, not a number to improvise in application code.

Measure security and friction before copying this design

Notebook-to-prod discipline starts with a small state machine and an eval set, then grows around observed failure modes. Build fixtures for a lost email with a valid passkey, a compromised old email, two subjects that once shared an address, an expired single-use token, simultaneous token redemption, a session minted one millisecond before epoch rotation, and a deletion event delivered twice. Include adversarial enumeration probes and compare response distributions, not just response strings.

Measure recovery completion rate, abandonment by step, support escalation rate, challenge replay attempts, false acceptance confirmed by investigation, time until every session path rejects access, and deletion-consumer acknowledgment lag. Slice results by recovery route and account-risk tier. A lower-friction path is valuable only while its takeover signal stays inside an agreed risk budget; a secure path that permanently locks out legitimate players is also failing.

Prompt-cost awareness belongs here if an AI support assistant summarizes evidence or guides agents. Keep the model outside the authorization decision. Feed it redacted, bounded fields; evaluate prompt-injection and data-leak cases; log the policy decision separately from generated prose; and require a deterministic service to accept or reject recovery. Token cost is worth measuring, but it is secondary to false acceptance, privacy exposure, and review consistency.

The architecture has real limits. A session epoch works well when validators can reach fresh state, but it is a poor fit for long-offline clients that must validate locally. Manual review can recover high-value accounts with no surviving authenticator, but it is expensive, slow, and vulnerable to social engineering. Stick with automated recovery when independent verified factors survive; use trained manual review for carefully scoped exceptions; and accept that some low-evidence cases should remain unrecoverable. Continuity is a goal, not permission to lower the proof bar until every request succeeds.

Ship only after the eval harness demonstrates the three promises together: mutable addresses do not own identity, recovery cannot preserve an attacker's sessions, and deletion closes access before data cleanup fans out.

References

Further reading

Top comments (0)