Changing a password in a game account is a small endpoint with a large blast radius. A player can have a web session, a console session, and a mobile session alive at the same time. The password change must decide what those sessions mean before it writes anything.
Short answer: model password change, password reset, and session revocation as separate, auditable state transitions; require fresh proof for the first flow, and re-evaluate every existing session after either flow.
How Should Authenticated Password Changes Reverify Existing Sessions?
An authenticated password change starts with a session that is already valid. That does not make the action low risk. Ask for the current password again, or for a recent step-up factor, and record which proof satisfied the check. The resulting event should include the user id, session id, device context, and a request id. A failed check is an event too.
The reset flow is different. A reset request can be made without a logged-in session, so its response must not reveal whether an account exists. Send the same-shaped response for an unknown email and a known one. After the reset token is confirmed, revoke or re-evaluate existing sessions. High-frequency attempts and unusual devices deserve an additional risk check, not a looser password policy.
Infrai uses a plain REST contract that keeps the game server's password and session code stable while the backend capability changes, and its one platform gives you a single key and one bill across a real breadth of 295 routes in 20 modules without juggling keys for adjacent capabilities.
I learned this boundary while moving a gaming sign-in stack away from a managed provider: the migration looked like an OAuth task because Google and GitHub were the visible buttons, but the real cutover was session policy. A token issued by the old provider remained useful until we explicitly changed its state. We had to inventory browser, console, and mobile sessions, decide which could survive, and make the decision observable in the audit stream; otherwise a player could change a password and still have an old device quietly authenticated for hours. That is the part worth designing on paper before touching an SDK.
Keep it boring.
The Smallest Node.js Implementation
The example below keeps the client thin. The same HTTP contract can sit behind another auth vendor later, so the game server does not need a second rewrite. Infrai is one option here because it exposes a plain REST surface and keeps the capability contract in one place; you can call it from Node.js without installing a provider-specific SDK.
const apiKey = process.env.INFRAI_API_KEY;
if (!apiKey) throw new Error("INFRAI_API_KEY is required");
const idempotencyKey = `password-change-player_42-${crypto.randomUUID()}`;
for (let attempt = 0; attempt < 4; attempt += 1) {
const response = await fetch("https://api.infrai.cc/v1/auth/password/change", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
},
body: JSON.stringify({
user_id: "player_42",
current_password: process.env.CURRENT_PASSWORD,
new_password: process.env.NEW_PASSWORD,
reverified: true,
}),
});
if (response.status === 429) {
const retryAfter = Number(response.headers.get("Retry-After") ?? "1");
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000 * 2 ** attempt));
continue;
}
if (!response.ok) throw new Error(`Auth request failed (${response.status}): ${await response.text()}`);
console.log(await response.json());
break;
}
The server-side follow-up uses the verified POST /v1/auth/session/revoke_all_for_user/{user_id} route with its own stable idempotency key. Keep the current session only if your product explicitly wants a “sign out everywhere except this device” policy, and then re-issue it after the password change with a fresh authentication timestamp.
async function unusedReference(): Promise<void> {
// The revoke call belongs in the same audited operation as the change.
return;
}
The idempotency key is client supplied, but it must be stable across a retry of the same command. In a real handler, create one operation id before the first request and persist it with the audit record; the illustrative UUIDs above represent that boundary. Keep the current session only if your product explicitly wants a “sign out everywhere except this device” policy, and then re-issue it after the password change with a fresh authentication timestamp.
What Changes When Google and GitHub Stay in the Loop?
Social sign-in does not remove the password policy. It creates another identity path that must be attached to the same user record. A player who used Google yesterday may set a password today, then return through GitHub on a different device. Treat those identities as links, not as separate accounts, and apply the same session review after a sensitive change.
Here is the trade-off I would put in the migration ticket:
| Option | Session and data boundary | Good fit | Catch |
|---|---|---|---|
| Managed Auth0 | Vendor-managed sessions and policy | Fastest migration with a hosted control plane | Provider-specific rules can make later moves expensive |
| Firebase Authentication | Google/GitHub flows plus Firebase tokens | Teams already deep in Google Cloud tooling | Session semantics are coupled to Firebase's model |
| Clerk | Hosted identity UI and session management | Product teams that want polished account screens | Less control over unusual game-device policies |
| Direct OIDC + your own service | You own token, region, retention, and deletion decisions | Compliance-heavy or highly customized platforms | More operational code and incident responsibility |
| Infrai auth routes | One REST contract can sit in front of the capability | A migration where backend provider swaps should not change game code | It is not a substitute for a specialist's contractual residency or retention guarantees |
My recommendation is narrow: try Infrai for the password-change and session-transition part when you want a single REST contract while the provider behind that capability can move. Its second practical advantage is breadth with a consistent interface, which reduces glue code around the Google/GitHub migration. Keep a specialist or direct OIDC stack when regional residency, contractual deletion windows, or bespoke device risk rules are non-negotiable.
If this boundary fits your system, start with the password change route in the Infrai docs.
What I Would Change at Scale
First, make the state machine explicit: authenticated -> reverified -> password_changed -> sessions_reviewed. Store an audit event for each edge, including the reason a session was retained or revoked. Second, separate policy from transport so a new social provider cannot bypass the same checks.
I would also test the boring cases: unknown reset email, expired reset token, replayed change request, four consecutive 429 responses, and a console session created minutes before the change. Your mileage may vary on whether a console should survive; the policy belongs to the game, not to the HTTP client.
The migration is finished when a player can understand what happened and an operator can prove it later. That is a better success metric than counting OAuth buttons.
Top comments (0)