feat(web,server): add email/password authentication#571
Conversation
Enable email & password login alongside existing GitHub/Vercel OAuth. Closes #562
|
🚅 Deployed to the openchat-pr-571 environment in OpenChat
|
…vigation - Normalize auth error messages to prevent email enumeration attacks - Make refetchSession return boolean, only navigate on success - Add TODO for email verification before production
Greptile OverviewGreptile SummaryThis PR successfully adds email/password authentication alongside the existing GitHub/Vercel OAuth, enabling users to sign up and sign in without requiring a third-party account. Key Changes
Integration Notes
Issues Found
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant U as User
participant SP as Sign In Page
participant AC as Auth Client
participant BA as Better Auth
participant US as User Sync
participant DB as Convex DB
U->>SP: Enter form data
alt Registration
SP->>AC: signUpWithEmail()
AC->>BA: POST sign up
BA-->>AC: Response OK
else Login
SP->>AC: signInWithEmail()
AC->>BA: POST sign in
BA-->>AC: Response OK
end
SP->>AC: refetchSession()
AC->>BA: GET session info
BA-->>AC: Return data
SP->>SP: Navigate home
US->>DB: Sync user data
DB-->>US: Confirm sync
|
| const success = await refetchSession(); | ||
| if (success) { |
There was a problem hiding this comment.
After successful email auth, analytics.signedIn() is not called, but it is called for OAuth flows in StableAuthProvider (line 169 in auth-client.tsx)
| const success = await refetchSession(); | |
| if (success) { | |
| await refetchSession(); | |
| analytics.signedIn(); | |
| navigate({ to: "/" }); |
apps/web/src/routes/auth/sign-in.tsx
Outdated
|
|
||
| try { | ||
| if (isSignUp) { | ||
| const { error } = await signUpWithEmail(email, password, name || email.split("@")[0]); |
There was a problem hiding this comment.
Defaulting the name to email.split("@")[0] could fail if the email doesn't contain @ (though the browser's type="email" validation should prevent this)
Better to be defensive:
| const { error } = await signUpWithEmail(email, password, name || email.split("@")[0]); | |
| const { error } = await signUpWithEmail(email, password, name || email.split("@")[0] || "User"); |
| const success = await refetchSession(); | ||
| if (success) { | ||
| navigate({ to: "/" }); | ||
| } else { |
There was a problem hiding this comment.
The catch block swallows the actual error, making debugging harder. Consider logging it:
| } else { | |
| } catch (err) { | |
| console.error("Email auth failed:", err); | |
| setEmailError(isSignUp ? "Sign up failed. Please try again." : "Sign in failed. Please try again."); |
| id="password" | ||
| type="password" | ||
| placeholder="Min. 8 characters" | ||
| value={password} |
There was a problem hiding this comment.
HTML5 minLength provides client-side validation, but Better Auth config specifies maxPasswordLength: 128 (line 92 in auth.ts). Add maxLength for consistency:
| value={password} | |
| minLength={8} | |
| maxLength={128} |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
- Track analytics.signedIn() for email auth flow - Add defensive fallback for name derivation from email - Log errors in catch block for debugging - Add maxLength=128 to password input matching server config
🚀 Preview Deployment Ready
Convex Preview Backend
🤖 Deployed automatically by GitHub Actions |
requireEnv('GITHUB_CLIENT_ID') threw during Convex module analysis before
env vars were available, preventing code from deploying to preview environments.
Now uses conditional spread (like Vercel OAuth) so GitHub OAuth is only
configured when credentials exist. Also restructures the preview deploy
workflow to: deploy → set env vars → redeploy with env vars.
--preview-create generates a new Convex deployment each call with a different URL. The redeploy step was creating a second deployment without the env vars set in the previous step. Since createAuth() reads env vars at runtime, a single deploy + env var set is sufficient.
Summary
Changes
apps/server/convex/auth.tsemailAndPassword: { enabled: true }with 8-128 char password constraintsapps/web/src/lib/auth-client.tsxsignInWithEmail()andsignUpWithEmail()helper functionsapps/web/src/routes/auth/sign-in.tsxHow it works
/Closes #562