You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, password registrants land with display_name = null and show up as their raw email everywhere (navbar.tsx already falls back: {auth.displayName ?? auth.email}). Google and Steam OAuth users typically get a display_name populated from the provider's profile, but the gap is real for password sign-ups.
Goal
Capture or suggest a display name without blocking the registration or post-OAuth flow. Also add a "username" identity that can be used to log in alongside email.
Scope
Frontend (this repo)
Optional display-name field on /register — between the email and password inputs. Empty submission is fine; backend already accepts null. Helper text: "What others will see — you can change this later."
Nudge banner on /profile when display_name is null — same shape as the existing consent-stale banner in profile-page.tsx. Copy idea: "You're showing up as your email. Pick a display name to personalize your account." Dismissible per session via localStorage.
Login by email OR username — login-page.tsx's email input becomes "Email or username". Backend handles the lookup; frontend just sends whatever the user typed. Form validation drops the type="email" constraint or makes it conditional.
Backend (auth-api, separate ticket needed)
The API doesn't currently have a username concept distinct from display_name. Open questions for the backend:
Is username the same column as display_name, or separate?
Same: display_name becomes unique (case-insensitive), with username-style validation (alphanumeric + _ + -, length cap). Simpler data model but constrains display-name freedom.
Separate: new username column, unique, used for login. display_name stays freeform. More flexibility, slightly more UI.
Default value: per Daisy's note, default to the email (or email's local-part) as the initial username, with the option to override later. Probably the local-part is what people expect (alice@example.com → alice).
Email change syncs username when identical: if the user hasn't customized their username and changes their email, the username should follow. (Email change isn't implemented yet — flag this so it's not lost.)
/auth/jwt/login would need to accept either format. FastAPI-Users' default username field is the email; we'd need to override the user manager's authenticate method.
Constraint: don't break the cross-origin redirect flow
When a user is at a consumer app (e.g. hera-streamer-invitational-2026.criticalbit.gg) and clicks "Sign in", they land at auth.criticalbit.gg/login?redirect=https://hera-… and after a successful sign-in get bounced back. New users registering through this flow must not be interrupted by a forced onboarding step — the banner approach on /profile is fine (they may never see it before bouncing out), a modal/forced-pick page is not.
register-page.tsx currently does not preserve the ?redirect= param across the register→login→/profile sequence — that's a separate bug, but a fix here might want to handle it.
Out of scope / explicit non-goals
Forced display-name picker as an onboarding step. Banner is the chosen approach (lower friction, doesn't block redirect flow).
Email change UI (not implemented yet — but the username-syncs-with-email rule should be captured for whoever picks that up).
Username uniqueness migration for existing users (probably need a backfill; depends on the same-vs-separate decision above).
Order of operations
Backend designs username (same vs separate from display_name), ships the auth-by-username support and the email-change sync rule.
Currently, password registrants land with
display_name = nulland show up as their raw email everywhere (navbar.tsxalready falls back:{auth.displayName ?? auth.email}). Google and Steam OAuth users typically get adisplay_namepopulated from the provider's profile, but the gap is real for password sign-ups.Goal
Capture or suggest a display name without blocking the registration or post-OAuth flow. Also add a "username" identity that can be used to log in alongside email.
Scope
Frontend (this repo)
/register— between the email and password inputs. Empty submission is fine; backend already acceptsnull. Helper text: "What others will see — you can change this later."/profilewhendisplay_nameis null — same shape as the existing consent-stale banner inprofile-page.tsx. Copy idea: "You're showing up as your email. Pick a display name to personalize your account." Dismissible per session via localStorage.login-page.tsx's email input becomes "Email or username". Backend handles the lookup; frontend just sends whatever the user typed. Form validation drops thetype="email"constraint or makes it conditional.Backend (auth-api, separate ticket needed)
The API doesn't currently have a
usernameconcept distinct fromdisplay_name. Open questions for the backend:usernamethe same column asdisplay_name, or separate?display_namebecomes unique (case-insensitive), with username-style validation (alphanumeric +_+-, length cap). Simpler data model but constrains display-name freedom.usernamecolumn, unique, used for login.display_namestays freeform. More flexibility, slightly more UI.alice@example.com→alice)./auth/jwt/loginwould need to accept either format. FastAPI-Users' default username field is the email; we'd need to override the user manager's authenticate method.Constraint: don't break the cross-origin redirect flow
When a user is at a consumer app (e.g.
hera-streamer-invitational-2026.criticalbit.gg) and clicks "Sign in", they land atauth.criticalbit.gg/login?redirect=https://hera-…and after a successful sign-in get bounced back. New users registering through this flow must not be interrupted by a forced onboarding step — the banner approach on/profileis fine (they may never see it before bouncing out), a modal/forced-pick page is not.register-page.tsxcurrently does not preserve the?redirect=param across the register→login→/profile sequence — that's a separate bug, but a fix here might want to handle it.Out of scope / explicit non-goals
Order of operations
display_name), ships the auth-by-username support and the email-change sync rule./registerfield (works regardless of Add auth pages (login, register, profile, Google callback) #1)./profilenudge banner (works regardless of Add auth pages (login, register, profile, Google callback) #1)./loginto accept email-or-username (depends on Add auth pages (login, register, profile, Google callback) #1).Steps 2 and 3 are mechanically simple and can ship today; 1 and 4 are coupled.
Files likely touched (this repo)
src/pages/register/register-page.tsx— add optional inputsrc/pages/profile/profile-page.tsx— add nudge bannersrc/pages/login/login-page.tsx— relabel email field to "email or username", droptype="email"src/lib/auth.tsx— no change needed unlessdisplay_namebecomes the usernameag-tech-group/criticalbit-auth-apifor the backend work