Firebase auth migration
The custom JWT/Passport authentication system has been replaced with Firebase Authentication as the identity provider. Users sign in via Firebase's Google popup flow client-side. The backend validates Firebase ID tokens rather than issuing its own JWTs — offloading session management, token rotation, and OAuth complexity to a production-grade identity service.
Existing users were migrated without data loss by matching on Google account ID. The migration is the second major auth pivot in the product's history: the first removed email/password login (April 20), this one moves session management out of the backend entirely. Less custom code, smaller attack surface, better token hygiene.
Even though email/password was already removed from the UI in April, it was still technically enabled in the Firebase console. The provider was explicitly disabled so no path to create or sign in with a password credential exists at the identity-provider level — not just at the UI level.
Disposable email blocking
A registration check now validates new accounts against a blocklist of known disposable email providers — Mailinator, 10-minute mail, and similar services. Accounts using disposable addresses are rejected at sign-up. A companion admin endpoint (DELETE /api/admin/users/:email) enables bulk-deleting accounts by email domain, useful for purging any disposable accounts that slipped through before the check was added.
Admin route hardening
All admin endpoints received a security pass:
- Rate limiting on the admin secret header — prevents brute-force enumeration of the admin secret via repeated requests
- Input sanitization on path parameters — path traversal and injection patterns are rejected before they reach the route handlers
- XSS fix for any admin-supplied values that were being reflected into API responses without escaping
Voice admin controls
Room owners and moderators can now mute individual users or the entire voice room. Four new socket events handle the moderation surface: mute_user, unmute_user, mute_all, and unmute_all. Server-side, a per-room adminMuted set tracks who has been muted by an admin. An admin_mute_change broadcast keeps all connected clients synchronized.
Admin mutes persist until explicitly removed — they're not overridden by the muted user toggling their own mic. This creates a meaningful distinction between a user voluntarily muting themselves and an admin enforcing silence.
EPIPE crash fix
The production server was crashing when a voice memo arrived with an audio format that ffmpeg couldn't parse. ffmpeg would exit early and close its stdin pipe before the server finished writing the audio buffer, producing an EPIPE error that propagated as an uncaught exception — triggering a graceful shutdown and dropping all active connections.
Two-layer fix: an error handler on ffmpeg.stdin suppresses the EPIPE at the source, and the global uncaughtException handler was updated to treat EPIPE as non-fatal (log and continue) rather than initiating a shutdown. Server restarts caused by malformed audio uploads are now impossible.
Multi-use invite links with user-controlled duration
The invite link system was redesigned for a more practical open-invite model. Previously, each link was single-use — accepting it marked it consumed and blocked everyone else. And the expiry was hardcoded at 10 minutes with no UI to change it.
The new model: open invite links are multi-use. Any number of people can join using the same link within the active window. Links with no target user or email skip the accepted check entirely — they stay valid until they expire. Room owners can drop a link in a Discord, tweet it, or share it in a group chat and have multiple people join, rather than generating a fresh link per person.
The LinkModal now shows an "Expires after" dropdown with options from 10 minutes to 24 hours. The selected duration is passed to create_room_link, which clamps it to 1–1440 minutes and stores the corresponding expiresAt.
Why it matters
Firebase auth offloads session management, token rotation, and OAuth flows to a production-grade identity service — less custom auth code to maintain, audit, and protect. The multi-use invite links change the social dynamics of the product: sharing a GroupGPT room is now as simple as sharing a link, with no per-person invite management required. Combined with user-controlled expiry, room owners have full control over the access window without needing to touch the dashboard.