Authentication architecture
The authentication system consists of three main parts:- Supabase client - Handles communication with Supabase Auth
- Auth provider - Manages auth state and exposes it via React context
- Auth guards - Protect routes based on authentication status
Auth provider
TheAuthProvider wraps your application and provides authentication state to all components.
How it works
src/features/auth/providers/auth-provider.tsx
Key features
Session restoration
Session restoration
On mount, the provider checks for an existing session using
supabase.auth.getSession(). If a valid session exists (from localStorage), the user is automatically logged in.Real-time auth state
Real-time auth state
The provider subscribes to auth state changes using
onAuthStateChange(). This ensures the UI updates immediately when:- User signs in
- User signs out
- Session expires
- User signs in on another tab
User object mapping
User object mapping
Supabase returns a full auth user object, but Goalst extracts only the necessary fields:
Using the auth context
Access authentication state in any component using theuseAuth hook:
Hook return values
The currently authenticated user, or
null if not authenticated.true while checking for an existing session on initial load. Use this to show a loading state.Function to sign the current user out. This clears the session and updates the auth state.
Sign up flow
Users create accounts through the signup screen, which uses theuseSignup hook:
src/features/auth/api/use-signup.ts
User submits the form
The signup form collects email and password, validates them, and calls
useSignup.Email confirmation (optional)
If email confirmation is enabled in Supabase, the user receives a confirmation email. Otherwise, they’re immediately authenticated.
Auth state updates
The
onAuthStateChange listener fires, updating the AuthProvider with the new user.Sign in flow
Returning users sign in using theuseLogin hook:
src/features/auth/api/use-login.ts
Supabase validates credentials
The
signInWithPassword() method checks the credentials against the database.Route protection
Goalst uses anAuthGuard component to protect authenticated routes:
src/features/auth/guards/auth-guard.tsx
How it works
Check loading state
While
loading is true, display a loading spinner. This prevents flickering during session restoration.Usage in routes
Wrap protected routes with theAuthGuard:
Guest guard
The opposite ofAuthGuard, the GuestGuard redirects authenticated users away from public pages like login and signup.
Use
GuestGuard on routes like /login and /signup to prevent authenticated users from accessing them.Sign out
Users can sign out from any component with access to the auth context:- Calls
supabase.auth.signOut()to clear the session - Updates the auth context to set
usertonull - Triggers a redirect to the login page (if on a protected route)
Session management
Supabase handles session management automatically:- Storage: Sessions are stored in localStorage by default
- Expiration: Sessions expire after a configurable period (default: 1 hour)
- Refresh: Supabase automatically refreshes tokens before expiration
- Cross-tab sync: Auth state syncs across browser tabs
Error handling
BothuseLogin and useSignup throw errors that can be caught:
| Error | Cause |
|---|---|
Invalid login credentials | Wrong email or password |
Email not confirmed | User hasn’t verified their email |
User already registered | Email already exists (signup) |
Security best practices
Use HTTPS in production
Always serve your application over HTTPS to prevent session hijacking.
Enable email confirmation
Require email verification for new accounts to prevent abuse.
Implement password requirements
Enforce minimum password length and complexity.
Use Row Level Security
Configure RLS policies in Supabase to protect user data.
Next steps
Deployment
Deploy your authenticated Goalst application to production