Supabase Auth
Complete authentication system with Supabase including sign in/up, password reset, OTP verification, magic links, and OAuth providers (Google, GitHub). Features passwordless options, comprehensive error handling, and responsive UI.
Preview
Overview
A complete authentication system with Supabase including sign in/up, password reset, OTP verification, magic links, and OAuth providers (Google, GitHub). Features passwordless options, comprehensive error handling, and responsive UI.
This comprehensive auth system provides:
- Multiple Sign-in Methods: Magic links, OTP codes, password-based auth, and OAuth
- Complete User Flows: Sign up, sign in, password reset, email verification
- Modern UI: Built with shadcn/ui components for a polished experience
- Error Handling: Comprehensive error states with user-friendly messages
- Security Best Practices: Rate limiting, secure redirects, and proper session management
- Responsive Design: Mobile-first design that works on all devices
Installation
npx shadcn@latest add https://jt-components.vercel.app/r/supabase-auth.jsonpnpm dlx shadcn@latest add https://jt-components.vercel.app/r/supabase-auth.jsonyarn dlx shadcn@latest add https://jt-components.vercel.app/r/supabase-auth.jsonbunx --bun shadcn@latest add https://jt-components.vercel.app/r/supabase-auth.jsonEnvironment Variables
Make sure to add the following environment variables to your .env.local file:
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
NEXT_PUBLIC_SITE_URL=http://localhost:3000Supabase Setup
1. Enable Authentication Providers
In your Supabase dashboard, go to Authentication > Providers and enable:
- Email (for magic links and OTP)
- Google (optional)
- GitHub (optional)
2. Configure OAuth Providers
For Google OAuth:
Site URL: http://localhost:3000
Redirect URLs: http://localhost:3000/auth/callbackFor GitHub OAuth:
Site URL: http://localhost:3000
Redirect URLs: http://localhost:3000/auth/callback3. Email Templates
Configure your email templates in Authentication > Email Templates for:
- Magic Link
- Confirm signup
- Reset password
Usage
Basic Authentication Flow
The auth system provides multiple sign-in options:
// Sign in with magic link
import { signInWithMagicLink } from '@/actions/auth'
export default function SignInForm() {
return (
<form action={signInWithMagicLink}>
<input type="email" name="email" required />
<button type="submit">Send Magic Link</button>
</form>
)
}Password Authentication
// Sign in with password
import { signInWithPassword } from '@/actions/auth'
export default function PasswordSignIn() {
return (
<form action={signInWithPassword}>
<input type="email" name="email" required />
<input type="password" name="password" required />
<button type="submit">Sign In</button>
</form>
)
}OTP Verification
// Verify OTP code
import { signInWithOTP } from '@/actions/auth'
export default function OTPForm() {
return (
<form action={signInWithOTP}>
<input type="email" name="email" required />
<button type="submit">Send OTP</button>
</form>
)
}OAuth Providers
// Social authentication
import { signInWithGoogle, signInWithGithub } from '@/actions/auth'
export default function SocialAuth() {
return (
<div>
<button onClick={signInWithGoogle}>Sign in with Google</button>
<button onClick={signInWithGithub}>Sign in with GitHub</button>
</div>
)
}Sign Out
// Sign out user
import { signOut } from '@/actions/auth'
export default function SignOutButton() {
return (
<form action={signOut}>
<button type="submit">Sign Out</button>
</form>
)
}Authentication Pages
The system includes complete authentication pages:
Sign In Page (/signin)
- Magic link and OTP options (recommended)
- Link to password-based sign in
- OAuth provider buttons
- Error handling and rate limiting
Sign Up Page (/signup)
- Passwordless registration options
- Link to password-based sign up
- OAuth provider buttons
- Account verification flow
Password Pages
/signin/password- Password-based sign in/signup/password- Password-based sign up/signin/password/reset- Password reset request
Verification Pages
/verify-email- Email verification confirmation/verify-otp- OTP code verification/update-password- Password update form
Middleware Integration
Add the auth middleware to your middleware.ts:
import { updateSession } from '@/lib/supabase/middleware'
export async function middleware(request) {
return await updateSession(request)
}
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
],
}Source Code
Server Actions
The auth system includes comprehensive server actions:
Authentication Actions
signInWithMagicLink()- Send magic link emailsignInWithOTP()- Send OTP codesignInWithPassword()- Password-based sign insignUpWithPassword()- Password-based sign upsignInWithGoogle()- Google OAuthsignInWithGithub()- GitHub OAuthsignOut()- Sign out user
Password Management
requestPasswordReset()- Request password resetupdateUserPassword()- Update user password
Customization
Styling
All components use shadcn/ui classes and can be customized via your CSS variables:
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
/* ... */
}Branding
Update the auth layout in app/(auth)/layout.tsx:
export default function AuthLayout({ children }) {
return (
<main className="flex min-h-screen w-full flex-col items-center justify-center p-4">
<YourLogo className="w-10 h-10" />
<h1 className="text-2xl font-bold">Your App Name</h1>
<p className="text-sm text-muted-foreground">
Your app description
</p>
{children}
</main>
)
}Redirects
Customize redirect URLs in the auth actions:
// Custom redirect after sign in
const { error } = await supabase.auth.signInWithPassword({
email: result.data.email,
password: result.data.password,
})
if (!error) {
redirect('/dashboard') // Custom redirect
}Examples
Protected Route
// app/dashboard/page.tsx
import { createClient } from '@/lib/supabase/server'
import { redirect } from 'next/navigation'
export default async function Dashboard() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
redirect('/signin')
}
return (
<div>
<h1>Welcome, {user.email}</h1>
</div>
)
}User Profile
// components/user-profile.tsx
import { createClient } from '@/lib/supabase/client'
import { useEffect, useState } from 'react'
export default function UserProfile() {
const [user, setUser] = useState(null)
const supabase = createClient()
useEffect(() => {
const getUser = async () => {
const { data: { user } } = await supabase.auth.getUser()
setUser(user)
}
getUser()
}, [supabase])
return user ? (
<div>
<p>Signed in as: {user.email}</p>
</div>
) : (
<div>Not signed in</div>
)
}Auth State Listener
// hooks/use-auth.ts
import { createClient } from '@/lib/supabase/client'
import { useEffect, useState } from 'react'
export function useAuth() {
const [user, setUser] = useState(null)
const supabase = createClient()
useEffect(() => {
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(event, session) => {
setUser(session?.user ?? null)
}
)
return () => subscription.unsubscribe()
}, [supabase])
return { user }
}FAQ
Some common issues and solutions.
Last updated on