Authentication & Notifications
Configure authentication and notification settings
Overview
CritForge's auth notification system provides visual feedback for authentication events using toast notifications. It addresses the UX gap where users received no confirmation after completing auth actions like email verification or password reset.
Architecture
Components
AuthNotifications Component
Location: src/components/auth/AuthNotifications.tsx
Client component that monitors URL query parameters and displays toast notifications for auth events.
Features:
- Monitors URL query params for auth success/error states
- Uses Sonner toast library (already integrated in CritForge)
- Themed toasts with parchment gradient backgrounds
- Custom icons per auth event type
- Auto-dismisses after 4-5 seconds
- No visual UI - pure side-effects component
Supported Query Parameters:
| Parameter | Trigger | Notification |
|---|---|---|
verified=true | Email verification (new user) | Email verification success |
welcome=true | New user signup | Enhanced welcome message |
password_reset=true | Password reset completion | Password updated confirmation |
email_updated=true | Email change confirmation | Email update success |
magic_link=true | Magic link authentication | Magic link login success |
reauth=true | Session renewal | Session renewed confirmation |
error=* | Auth errors | Error notification (various types) |
Toast Styling:
- Success toasts use gradient backgrounds (green/blue/purple/amber to parchment)
- Custom Lucide icons per event type
- Themed to match CritForge's D&D parchment aesthetic
- Accessible with ARIA live regions (handled by Sonner)
Integration Points
Layout Integration
Location: src/app/[locale]/layout.tsx
<Suspense fallback={null}>
<AuthNotifications />
</Suspense>
- Wrapped in Suspense boundary (required for
useSearchParams()) - Global scope - monitors all pages for auth params
- Silent fallback (no loading state needed)
Auth Confirmation Route
Location: src/app/api/auth/confirm/route.ts
Enhanced to handle multiple auth types:
switch (type) {
case 'signup':
redirectTo.searchParams.set('welcome', 'true');
redirectTo.searchParams.set('verified', 'true');
break;
case 'email_change':
redirectTo.searchParams.set('email_updated', 'true');
break;
case 'recovery':
// Redirects to reset-password page
break;
case 'magiclink':
redirectTo.searchParams.set('magic_link', 'true');
break;
}
Password Reset Flow
Location: src/app/[locale]/reset-password/page.tsx
After successful password update:
router.push("/generate/npc?password_reset=true");
Internationalization
Location: src/locales/*/auth.json
All auth notifications are fully translated across 5 locales:
en-US- English (United States)fr-FR- French (France)es-ES- Spanish (Spain)de-DE- German (Germany)pt-BR- Portuguese (Brazil)
Translation Keys:
{
"auth": {
"notifications": {
"emailVerified": "Email Verified Successfully",
"emailVerifiedDescription": "Your email has been confirmed...",
"emailVerifiedWelcome": "Welcome to CritForge!",
"emailVerifiedWelcomeDescription": "Your email is verified...",
"passwordReset": "Password Reset Complete",
"passwordResetDescription": "Your password has been updated...",
"error": {
"generic": "Authentication Error",
"verificationFailed": "Verification Failed",
"invalidLink": "Invalid Link",
"sessionExpired": "Session Expired",
"rateLimit": "Too Many Requests"
}
}
}
}
User Flows
Email Verification (New User)
- User signs up at
/signup - Backend sends verification email via Supabase
- User clicks link in email
- Supabase redirects to
/api/auth/confirm?token_hash=...&type=signup - Backend verifies token and redirects to
/generate/npc?welcome=true&verified=true AuthNotificationscomponent detects params- Toast displays: "Welcome to CritForge!" with celebratory message
- Auto-dismisses after 5 seconds
Password Reset
- User requests reset at
/reset-password - User receives email with recovery link
- User clicks link → redirects to
/api/auth/confirm?token_hash=...&type=recovery - Backend redirects to
/reset-password?type=recovery - User sets new password
- Page redirects to
/generate/npc?password_reset=true - Toast displays: "Password Reset Complete"
Email Change
- User changes email in settings
- Supabase sends confirmation email
- User clicks link →
/api/auth/confirm?token_hash=...&type=email_change - Backend redirects to
/settings?email_updated=true - Toast displays: "Email Address Updated"
Magic Link Login
- User requests magic link at login
- User clicks link in email →
/api/auth/confirm?token_hash=...&type=magiclink - Backend redirects to
/dashboard?magic_link=true(or custom next URL) - Toast displays: "Successfully Signed In"
Design Decisions
Why Toast Notifications?
Considered Approaches:
- Toast/Notification (Chosen)
- Banner (Persistent at top)
- Modal Dialog (Blocking)
Rationale:
- Non-blocking: Users can immediately interact with the page
- Celebratory: Success events deserve positive reinforcement
- Consistent: Matches existing toast usage in CritForge (save success, errors, etc.)
- Accessible: Sonner provides ARIA live regions out-of-the-box
- Auto-dismissing: Reduces UI clutter after initial confirmation
Why Query Parameters?
Alternatives Considered:
- Session storage (not SSR-friendly)
- Cookies (requires additional cleanup)
- Global state (overkill for transient notifications)
Benefits:
- Works with server-side redirects
- No additional state management
- URL parameters are ephemeral (disappear on navigation)
- Easy to debug (visible in URL)
Redirect Destinations
| Auth Event | Redirect To | Reason |
|---|---|---|
| Email verification (new user) | /generate/npc | Immediately engage user with core feature |
| Password reset | /generate/npc | Return to productive state |
| Email change | /settings | Keep user in settings context |
| Magic link | /dashboard or custom | Flexible based on user intent |
Theme Integration
Parchment Gradients
Each auth event type uses a themed gradient that transitions to CritForge's parchment background:
// Email verification
className: "border-green-200 bg-gradient-to-br from-green-50 to-amber-50"
// Password reset
className: "border-blue-200 bg-gradient-to-br from-blue-50 to-amber-50"
// Email update
className: "border-purple-200 bg-gradient-to-br from-purple-50 to-amber-50"
// Magic link
className: "border-amber-200 bg-gradient-to-br from-amber-50 to-yellow-50"
Icons
Custom Lucide icons per event type:
- Email verification:
CheckCircle2(green) - Password reset:
Key(blue) - Email update:
Mail(purple) - Magic link:
Sparkles(amber) - Reauthentication:
Shield(indigo)
Future Enhancements
Potential Additions
- OAuth Success: Add notifications for Google/Discord login
- 2FA Events: Confirm 2FA setup/disable
- Account Deletion: Confirm account deletion request sent
- Trial Conversion: Celebrate upgrade from trial to premium
- Reward Unlocks: Notify when beta tester rewards are granted
Analytics Integration
Track notification engagement:
- Which auth events users complete most
- Time between email send and verification click
- A/B test different notification copy
Customization Options
Future user preferences:
- Disable auth notifications (for power users)
- Sound effects on success (optional)
- Persistent notifications until dismissed (accessibility option)
Testing
Manual Testing Checklist
Email Verification:
- Sign up with new email
- Click verification link in email
- Verify "Welcome to CritForge!" toast appears
- Check toast auto-dismisses after 5 seconds
Password Reset:
- Request password reset
- Click link in email
- Set new password
- Verify "Password Reset Complete" toast appears on redirect
Error States:
- Use expired verification link
- Verify error toast appears on login page
- Check error message is descriptive
Automated Testing
E2E Test Pattern (Playwright):
test('email verification shows success toast', async ({ page }) => {
await page.goto('/generate/npc?verified=true&welcome=true');
// Wait for toast to appear
await expect(page.getByRole('status')).toContainText('Welcome to CritForge!');
// Verify toast auto-dismisses
await expect(page.getByRole('status')).toBeHidden({ timeout: 6000 });
});
Troubleshooting
Toast Not Appearing
Possible Causes:
- Sonner not loaded (check
<Toaster />in layout) - Suspense boundary missing (causes hydration error)
- Translation keys missing in locale file
- Query params not set in redirect URL
Debug Steps:
// Add to AuthNotifications component
useEffect(() => {
console.log('[AUTH_NOTIFICATIONS] Query params:', {
verified: searchParams?.get('verified'),
welcome: searchParams?.get('welcome'),
// ... other params
});
}, [searchParams]);
Duplicate Toasts
Cause: React Strict Mode triggers effects twice in development
Solution: Sonner automatically deduplicates, but verify with:
toast.success(message, {
id: 'email-verified', // Unique ID prevents duplicates
// ... other options
});
Translation Missing
Error: [missing: "auth.notifications.emailVerified" translation]
Fix: Ensure all locale files have complete auth.notifications object.
Related Documentation
- Sonner Configuration:
src/components/ui/sonner.tsx - Auth Flow:
src/app/api/auth/confirm/route.ts - Theme System:
docs/architecture/design-system.md - i18n Setup:
src/i18n/routing.ts
Changelog
2026-02-04 - Initial Implementation
- Created AuthNotifications component
- Added i18n translations for 5 locales
- Enhanced auth confirmation route
- Integrated into layout with Suspense boundary
- Documented auth notification system