6.2 KiB
Fix New User Signup Wizard Flow
Problem Summary
The new user signup wizard is broken:
- After Auth0 callback, users go to
/garageinstead of/verify-email - Users can access
/garage/*without verified email - Onboarding flow is bypassed entirely
- New Requirement: Block login completely at Auth0 for unverified users
Root Causes
- Auth0Provider.tsx:29 -
onRedirectCallbackdefaults to/garagewithout checking verification - App.tsx:472-481 - Callback route just shows "Processing login..." with no routing logic
- App.tsx:549+ - Protected routes have no email verification check
- Auth0 - No rule/action blocking unverified users from logging in
Implementation Plan
Phase 1: Auth0 Configuration (Manual Step)
Auth0 Dashboard -> Actions -> Flows -> Login
Create a Post Login Action to block unverified users:
exports.onExecutePostLogin = async (event, api) => {
if (!event.user.email_verified) {
api.access.deny('Please verify your email address before logging in. Check your inbox for a verification link.');
}
};
This ensures:
- Unverified users cannot get a JWT
- They see a clear error on the Auth0 login screen
- They must click the verification link before logging in
Phase 2: Update Signup Flow
After signup, redirect to a "Check Your Email" page (not /verify-email)
The new flow:
- User submits signup form
- Backend creates Auth0 user (unverified)
- Auth0 automatically sends verification email
- Frontend shows "Check Your Email" page with:
- Message: "We've sent a verification link to your email"
- Resend button (calls public resend endpoint)
- "Back to Login" button
- User clicks email link -> Auth0 marks as verified
- User can now login -> goes to /onboarding
Phase 3: Backend Changes
File: backend/src/features/auth/api/auth.routes.ts
- Add
POST /api/auth/resend-verification-public(no JWT required) - Takes email address, looks up user, resends verification
File: backend/src/features/auth/api/auth.controller.ts
- Add
resendVerificationPublichandler
File: backend/src/features/auth/domain/auth.service.ts
- Add
resendVerificationByEmailmethod
File: backend/src/features/auth/api/auth.routes.ts
- Add
GET /api/auth/user-status(JWT required) - Returns:
{ emailVerified, onboardingCompleted, email }
File: backend/src/core/plugins/auth.plugin.ts
- Add
/api/auth/user-statustoVERIFICATION_EXEMPT_ROUTES
Phase 4: Create Callback Handler
File: frontend/src/features/auth/pages/CallbackPage.tsx (NEW)
- Fetches user status after Auth0 callback
- Routes based on status:
- Not onboarded ->
/onboarding - Onboarded ->
/garage(or returnTo)
- Not onboarded ->
- Note: Unverified users never reach this (blocked by Auth0)
File: frontend/src/features/auth/mobile/CallbackMobileScreen.tsx (NEW)
- Mobile version
Phase 5: Update Auth0Provider
File: frontend/src/core/auth/Auth0Provider.tsx
Update onRedirectCallback (line 27-31):
const onRedirectCallback = (appState?: { returnTo?: string }) => {
navigate('/callback', {
replace: true,
state: { returnTo: appState?.returnTo || '/garage' }
});
};
Phase 6: Rename/Update Verify Email Page
File: frontend/src/features/auth/pages/VerifyEmailPage.tsx
- Rename concept to "Check Your Email" page
- Remove polling (user can't be authenticated)
- Show static message + resend button (calls public endpoint)
- Add "Back to Login" button
File: frontend/src/features/auth/mobile/VerifyEmailMobileScreen.tsx
- Same changes for mobile
Phase 7: Update App.tsx Routing
File: frontend/src/App.tsx
- Replace callback handling (lines 472-481) with CallbackPage
- Add onboarding guard after authentication check
- Remove email verification check from frontend (Auth0 handles it)
// After isAuthenticated check:
// Fetch onboarding status
// If not onboarded -> /onboarding
// Otherwise -> proceed to /garage
Phase 8: Create Supporting Files
File: frontend/src/core/auth/useUserStatus.ts (NEW)
- Hook for fetching user status
File: frontend/src/features/auth/api/auth.api.ts
- Add
getUserStatus() - Add
resendVerificationPublic(email)(no auth)
Files to Modify
Auth0 (Manual Configuration)
- Create Post Login Action to block unverified users
Backend
backend/src/features/auth/api/auth.routes.ts- Add endpointsbackend/src/features/auth/api/auth.controller.ts- Add handlersbackend/src/features/auth/domain/auth.service.ts- Add methodsbackend/src/core/plugins/auth.plugin.ts- Update exempt routes
Frontend
frontend/src/core/auth/Auth0Provider.tsx- Fix onRedirectCallbackfrontend/src/App.tsx- Add route guards and callback handlerfrontend/src/features/auth/pages/CallbackPage.tsx- NEWfrontend/src/features/auth/mobile/CallbackMobileScreen.tsx- NEWfrontend/src/features/auth/pages/VerifyEmailPage.tsx- Update to static pagefrontend/src/features/auth/mobile/VerifyEmailMobileScreen.tsx- Updatefrontend/src/core/auth/useUserStatus.ts- NEWfrontend/src/features/auth/api/auth.api.ts- Add functions
New User Flow (After Fix)
1. Signup form submission
2. -> POST /api/auth/signup (creates unverified Auth0 user)
3. -> Navigate to /verify-email (static "Check Your Email" page)
4. User clicks verification link in email
5. -> Auth0 marks user as verified
6. User clicks "Login" on /verify-email page
7. -> Auth0 login succeeds (user is now verified)
8. -> /callback page fetches status
9. -> Not onboarded? -> /onboarding
10. -> Complete onboarding -> /garage
Returning User Flow
1. Login attempt (unverified) -> Auth0 blocks with error message
2. Login attempt (verified, not onboarded) -> /callback -> /onboarding
3. Login attempt (verified, onboarded) -> /callback -> /garage
Testing Checklist
- Auth0 Action blocks unverified login with clear error
- Signup -> check-email page -> verify via email -> login works
- Resend verification from check-email page works
- Verified user (no onboarding) -> onboarding wizard
- Verified + onboarded user -> direct to garage
- Direct URL access to /garage -> requires login
- All flows work on mobile
- All flows work on desktop