Authentication Best Practices in Supabase
Authentication is the foundation of application security. Supabase provides a complete auth solution, but implementing it correctly requires understanding best practices. Let's dive into secure authentication patterns.
Understanding Supabase Auth
Supabase Auth provides:
- Email/password authentication
- OAuth providers (Google, GitHub, etc.)
- Magic links
- Phone authentication
- Multi-factor authentication
- Row Level Security integration
Email/Password Authentication
Implement secure password-based auth:
// Sign up
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'securePassword123!',
options: {
data: {
full_name: 'John Doe',
avatar_url: 'https://example.com/avatar.jpg'
}
}
})// Sign in const { data, error } = await supabase.auth.signInWithPassword({ email: 'user@example.com', password: 'securePassword123!' }) ```
Password Requirements
Enforce strong passwords:
- Minimum 8 characters
- Mix of uppercase, lowercase, numbers
- Special characters
- Not in common password lists
OAuth Integration
Add social login for better UX:
// Google OAuth
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: 'https://yourdomain.com/auth/callback'
}
})// GitHub OAuth const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'github', options: { scopes: 'repo read:user' } }) ```
Magic Links
Passwordless authentication:
const { data, error } = await supabase.auth.signInWithOtp({
email: 'user@example.com',
options: {
emailRedirectTo: 'https://yourdomain.com/welcome'
}
})
Session Management
Handle sessions securely:
// Get current session
const { data: { session } } = await supabase.auth.getSession()// Refresh session const { data, error } = await supabase.auth.refreshSession()
// Sign out const { error } = await supabase.auth.signOut() ```
Session Persistence
Configure session storage:
const supabase = createClient(url, key, {
auth: {
persistSession: true,
storageKey: 'my-app-auth',
storage: window.localStorage,
autoRefreshToken: true,
detectSessionInUrl: true
}
})
Protected Routes
Implement route protection in Next.js:
// middleware.ts
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
import { NextResponse } from 'next/server'export async function middleware(req) { const res = NextResponse.next() const supabase = createMiddlewareClient({ req, res }) const { data: { session } } = await supabase.auth.getSession() if (!session && req.nextUrl.pathname.startsWith('/dashboard')) { return NextResponse.redirect(new URL('/login', req.url)) } return res } ```
User Roles & Permissions
Implement role-based access:
-- Create roles table
CREATE TABLE user_roles (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users NOT NULL,
role TEXT NOT NULL CHECK (role IN ('admin', 'user', 'moderator')),
UNIQUE(user_id, role)
);-- Create policy CREATE POLICY "Users can view their own roles" ON user_roles FOR SELECT USING (auth.uid() = user_id); ```
Check roles in your application:
const checkUserRole = async (requiredRole: string) => {
const { data, error } = await supabase
.from('user_roles')
.select('role')
.eq('user_id', user.id)
.eq('role', requiredRole)
.single()
return !!data
}
Multi-Factor Authentication
Add an extra security layer:
// Enroll MFA
const { data, error } = await supabase.auth.mfa.enroll({
factorType: 'totp'
})// Verify MFA const { data, error } = await supabase.auth.mfa.verify({ factorId: data.id, code: '123456' }) ```
Email Verification
Ensure email ownership:
// Send verification email
const { data, error } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'password123',
options: {
emailRedirectTo: 'https://yourdomain.com/verify-email'
}
})// Check verification status const { data: { user } } = await supabase.auth.getUser() if (!user?.email_confirmed_at) { // Email not verified } ```
Password Reset
Implement secure password reset:
// Request reset
const { data, error } = await supabase.auth.resetPasswordForEmail(
'user@example.com',
{ redirectTo: 'https://yourdomain.com/reset-password' }
)// Update password const { data, error } = await supabase.auth.updateUser({ password: 'newSecurePassword123!' }) ```
Security Best Practices
- Always use HTTPS in production
- Implement rate limiting
- Log authentication events
- Use secure cookie settings
- Validate tokens server-side
- Implement session timeouts
- Monitor for suspicious activity
Monitoring & Logging
Track authentication events:
supabase.auth.onAuthStateChange((event, session) => {
console.log('Auth event:', event)
if (event === 'SIGNED_IN') {
// Log successful login
logAuthEvent('sign_in', session?.user.id)
}
if (event === 'SIGNED_OUT') {
// Clear local state
clearUserData()
}
})
Conclusion
Secure authentication requires attention to detail and following established patterns. Supabase provides the tools, but implementing them correctly is crucial. Start with these best practices and adapt them to your specific needs.