A production-ready Next.js authentication tutorial demonstrating Supabase auth flows with real session listeners.
This project showcases two authentication patterns using Supabase and Next.js 16:
- Email + Password - Classic credentials flow with Supabase-managed sessions and a React listener that never goes stale
- Google Login - Social login via OAuth with automatic UI sync powered by
onAuthStateChange
- ✅ Server-side authentication with Supabase SSR
- ✅ Client-side session management with React listeners
- ✅ Protected routes via Next.js proxy (middleware)
- ✅ Automatic token refresh handling
- ✅ Type-safe Supabase client setup
- Node.js 18+
- A Supabase project (create one here)
npm installCreate a .env.local file in the root directory:
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_keyYou can find these values in your Supabase project settings
- Enable Email provider in Authentication > Providers
- Enable Google provider in Authentication > Providers
- Add your redirect URL
- Add production redirect URL when deploying
npm run devOpen http://localhost:3000 to see the demo.
├── app/
│ ├── email-password/ # Email + Password demo
│ ├── google-login/ # Google OAuth demo
│ └── page.tsx # Home page with demo links
├── lib/
│ └── supabase/
│ ├── browser-client.ts # Client-side Supabase client
│ └── server-client.ts # Server-side Supabase client
└── proxy.ts # Next.js proxy for protected routes
- Used in Server Components and API routes
- Shares cookies via Next.js
cookies()API - Automatically refreshes tokens when needed
- Used in Client Components
- Singleton pattern for efficiency
- Works with React's
onAuthStateChangelistener
- Runs on every request
- Protects routes starting with
/protected - Redirects unauthenticated users to
/login
/email-password- Email + Password authentication demo/google-login- Google OAuth authentication demo
The email/password demo ships with a complete Supabase recovery experience:
- Click Forgot password? while in the sign-in view. The client calls
supabase.auth.resetPasswordForEmailand sends users to/email-password?password-reset=true. - Supabase emails the reset link. Configure the Auth Site URL and allowed Redirect URLs in your project so the link is accepted in local/dev/staging environments.
- Following the link both signs the user in and flags the recovery session. The page detects
#type=recoveryor thepassword-resetquery and surfaces the “Choose a new password” form even though a session exists. - Submitting that form calls
supabase.auth.updateUser({ password })and keeps the new session active so users stay logged in.
If you customize the route, update the redirectTo option and allowed redirect URLs in Supabase to match.
npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run lint- Run ESLint
- Next.js 16 - React framework with App Router
- Supabase - Authentication and backend
- TypeScript - Type safety
- Tailwind CSS - Styling