Email & Password
Traditional email and password authentication.
Note: This is mock/placeholder content for demonstration purposes.
Email and password authentication is the traditional way users sign up and sign in.
Overview
Email/password authentication provides:
- User registration with email verification
- Secure password storage
- Password reset functionality
- Session management
Sign Up Flow
User Registration
import { signUpAction } from '~/lib/auth/actions';
const result = await signUpAction({
email: 'user@example.com',
password: 'SecurePassword123!',
});
Server Action Implementation
'use server';
import { enhanceAction } from '@kit/next/actions';
import { z } from 'zod';
const SignUpSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
});
export const signUpAction = enhanceAction(
async (data) => {
const client = getSupabaseServerClient();
const { data: authData, error } = await client.auth.signUp({
email: data.email,
password: data.password,
options: {
emailRedirectTo: `${process.env.NEXT_PUBLIC_SITE_URL}/auth/callback`,
},
});
if (error) throw error;
return { success: true, data: authData };
},
{ schema: SignUpSchema }
);
Sign Up Component
'use client';
import { useForm } from 'react-hook-form';
import { signUpAction } from '../_lib/actions';
export function SignUpForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
const onSubmit = async (data) => {
const result = await signUpAction(data);
if (result.success) {
toast.success('Check your email to confirm your account');
}
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>Email</label>
<input
type="email"
{...register('email', { required: true })}
/>
{errors.email && <span>Email is required</span>}
</div>
<div>
<label>Password</label>
<input
type="password"
{...register('password', { required: true, minLength: 8 })}
/>
{errors.password && <span>Password must be 8+ characters</span>}
</div>
<button type="submit">Sign Up</button>
</form>
);
}
Sign In Flow
User Login
export const signInAction = enhanceAction(
async (data) => {
const client = getSupabaseServerClient();
const { error } = await client.auth.signInWithPassword({
email: data.email,
password: data.password,
});
if (error) throw error;
redirect('/home');
},
{ schema: SignInSchema }
);
Sign In Component
'use client';
export function SignInForm() {
const { register, handleSubmit } = useForm();
const onSubmit = async (data) => {
try {
await signInAction(data);
} catch (error) {
toast.error('Invalid email or password');
}
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
type="email"
{...register('email')}
placeholder="Email"
/>
<input
type="password"
{...register('password')}
placeholder="Password"
/>
<button type="submit">Sign In</button>
</form>
);
}
Email Verification
Requiring Email Confirmation
Configure in Supabase dashboard or config:
// config/auth.config.ts
export const authConfig = {
requireEmailConfirmation: true,
};
Handling Unconfirmed Emails
export const signInAction = enhanceAction(
async (data) => {
const client = getSupabaseServerClient();
const { data: authData, error } = await client.auth.signInWithPassword({
email: data.email,
password: data.password,
});
if (error) {
if (error.message.includes('Email not confirmed')) {
return {
success: false,
error: 'Please confirm your email before signing in',
};
}
throw error;
}
redirect('/home');
},
{ schema: SignInSchema }
);
Password Reset
Request Password Reset
export const requestPasswordResetAction = enhanceAction(
async (data) => {
const client = getSupabaseServerClient();
const { error } = await client.auth.resetPasswordForEmail(data.email, {
redirectTo: `${process.env.NEXT_PUBLIC_SITE_URL}/auth/reset-password`,
});
if (error) throw error;
return {
success: true,
message: 'Check your email for reset instructions',
};
},
{
schema: z.object({
email: z.string().email(),
}),
}
);
Reset Password Form
'use client';
export function PasswordResetRequestForm() {
const { register, handleSubmit } = useForm();
const onSubmit = async (data) => {
const result = await requestPasswordResetAction(data);
if (result.success) {
toast.success(result.message);
}
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
type="email"
{...register('email')}
placeholder="Enter your email"
/>
<button type="submit">Send Reset Link</button>
</form>
);
}
Update Password
export const updatePasswordAction = enhanceAction(
async (data) => {
const client = getSupabaseServerClient();
const { error } = await client.auth.updateUser({
password: data.newPassword,
});
if (error) throw error;
redirect('/home');
},
{
schema: z.object({
newPassword: z.string().min(8),
}),
}
);
Password Requirements
Validation Schema
const PasswordSchema = z .string() .min(8, 'Password must be at least 8 characters') .regex(/[A-Z]/, 'Password must contain an uppercase letter') .regex(/[a-z]/, 'Password must contain a lowercase letter') .regex(/[0-9]/, 'Password must contain a number') .regex(/[^A-Za-z0-9]/, 'Password must contain a special character');
Password Strength Indicator
'use client';
import { useState } from 'react';
export function PasswordInput() {
const [password, setPassword] = useState('');
const strength = calculatePasswordStrength(password);
return (
<div>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<div className="flex gap-1">
{[1, 2, 3, 4].map((level) => (
<div
key={level}
className={cn(
'h-1 flex-1 rounded',
strength >= level ? 'bg-green-500' : 'bg-gray-200'
)}
/>
))}
</div>
<span className="text-sm">
{strength === 4 && 'Strong password'}
{strength === 3 && 'Good password'}
{strength === 2 && 'Fair password'}
{strength === 1 && 'Weak password'}
</span>
</div>
);
}
Session Management
Checking Authentication Status
import { getSupabaseServerClient } from '@kit/supabase/server-client';
export async function requireAuth() {
const client = getSupabaseServerClient();
const { data: { user } } = await client.auth.getUser();
if (!user) {
redirect('/auth/sign-in');
}
return user;
}
Sign Out
export const signOutAction = enhanceAction(
async () => {
const client = getSupabaseServerClient();
await client.auth.signOut();
redirect('/auth/sign-in');
}
);
Security Best Practices
- Enforce strong passwords - Minimum 8 characters, mixed case, numbers, symbols
- Rate limit login attempts - Prevent brute force attacks
- Use HTTPS only - Encrypt data in transit
- Enable email verification - Confirm email ownership
- Implement account lockout - After failed attempts
- Log authentication events - Track sign-ins and failures
- Support 2FA - Add extra security layer