Most site owners would agree: properly implementing authentication is critical, yet can be an intimidating task.
By leveraging Supabase's robust authentication services and seamless NextJS integration, you can efficiently implement secure sign-in, authorization, and user management flows with minimal effort.
In this post, you'll learn step-by-step how to configure Supabase and NextJS to enable authentication on both client and server-side, securely manage user sessions, customize UI components, manage profiles, and more using easy-to-follow code examples and best practices.
Introduction to Supabase Auth and NextJS
Integrating authentication into a NextJS application provides critical security and access control. Supabase Auth makes adding authentication to NextJS apps simple and secure with features like password encryption, email verification, and API documentation.
When paired with NextJS, Supabase Auth offers realtime user session handling across pages without needing a custom server. Let's explore why integrating Supabase Auth benefits NextJS apps.
Exploring the Supabase Auth NextJS App Directory
Most NextJS projects have a pages
directory containing React components that render for each route. Supabase Auth fits nicely into this structure.
Some common places Supabase Auth code appears in NextJS apps:
_app.js
- Handles user sessions across every pagepages/dashboard.js
- Checks if a user is logged in before allowing dashboard accesspages/login.js
- Renders the login form and signs users inpages/profile.js
- Shows user data from the database
By centralizing auth logic instead of duplicating code, integrating Supabase Auth helps organize NextJS apps.
Benefits of Integrating Supabase Auth with NextJS
Supabase Auth offers many advantages over custom auth solutions:
- Automatic session handling - Get user state across all pages without an auth server using
useUser()
hooks andSessionContext
. - Secure password encryption - User passwords are securely hashed with bcrypt before storing in the database.
- Email verification - Verify user email addresses to prevent fake accounts.
- User management UI - Easily manage user accounts, profiles and permissions in the Supabase dashboard.
Overall, by handling tedius auth tasks, Supabase Auth lets developers focus on building great apps rather than complex infrastructure.
Let's walk through implementating Supabase Auth in a NextJS app step-by-step.
Does Supabase have authentication?
Supabase Auth provides easy-to-implement authentication for Next.js applications. It is built on top of OAuth and supports features like multi-factor authentication, magic links, and social logins.
Supabase generates typescript definitions based on your database schema. This allows for auto-complete and type safety when accessing the database from a Next.js frontend.
Here is an example of setting up Supabase client with Next.js API routes:
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!)
export default async function handler(req, res) {
const { data: { session } } = await supabase.auth.getSession()
if (!session) {
return res.status(401).json({ error: 'Unauthorized' })
}
// ...carry on with the request
}
This checks if there is an active user session before allowing the API route to execute.
Some key benefits of using Supabase Auth with Next.js:
- Works for both server-side rendering and static site generation
- Secure - protects API routes and data
- Simple setup with typescript support
- Features like magic links and social logins
So in summary, Supabase makes adding authentication to Next.js apps easy and secure. The integration works smoothly on the frontend and with API routes.
Does Next.js have authentication?
Next.js is a popular React framework that makes it easy to build web applications with features like server-side rendering and static site generation. While Next.js itself does not include built-in authentication, it has great integration with third-party authentication providers.
One popular authentication solution that works well with Next.js is Supabase. Supabase provides open-source authentication along with a fully managed Postgres database. Adding Supabase authentication to a Next.js application takes just a few steps.
Setting up Supabase
First, you'll need to create a new Supabase project. After logging into your Supabase dashboard:
- Create a new project
- Go to the Auth tab and enable email/password authentication under providers.
- Grab your API URL and public anon key from the project settings.
Next, install the Supabase JS client library:
npm install @supabase/supabase-js
Then initialize the client in your app using your project details:
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'https://your-project-id.supabase.co',
'your-public-anon-key'
)
Implementing Auth Flows
With Supabase set up, you can start using the auth
functions like signIn
and signOut
in your Next.js application.
For example, to add a sign in form:
async function signIn({ email, password }) {
const { error } = await supabase.auth.signIn({ email, password })
if (!error) {
router.push('/dashboard')
}
}
That covers the basics of adding authentication using Supabase and Next.js! With these building blocks, you can create secure user flows for login, signup, password recovery and more.
How would you implement secure authentication and authorization in a Next.js application?
Implementing secure authentication and authorization in a Next.js application can be achieved in a few ways, depending on your needs.
Use Supabase for Authentication
One great option is to use Supabase for authentication. Supabase makes it easy to add user management and authentication to your Next.js application.
To get started, you'll first need to create a Supabase project. Once your project is ready, install the Supabase JS library:
npm install @supabase/supabase-js
Then initialize the Supabase client in your app:
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
'YOUR_SUPABASE_URL',
'YOUR_SUPABASE_KEY'
)
Supabase offers a wide range of authentication options out of the box, including email/password, phone login, OAuth providers like Google and GitHub, and more.
For example, here is how you can implement a login form with email/password using Supabase:
async function signIn({ email, password }) {
const { data, error } = await supabase.auth.signIn({
email,
password,
})
}
Supabase seamlessly handles secure password storage, refresh tokens, email confirmations, and more.
Overall, Supabase auth provides a simple yet robust authentication system for Next.js apps. The Supabase JS library handles all of the complexities around implementing secure auth.
Use NextAuth.js
Another option is NextAuth.js, an open source authentication library designed for Next.js applications.
To get started with NextAuth.js, first install the library:
npm install next-auth
Then wrap your app in the NextAuthProvider
:
import { NextAuthProvider } from 'next-auth/client'
function MyApp({ Component, pageProps }) {
return (
<NextAuthProvider session={pageProps.session}>
<Component {...pageProps} />
</NextAuthProvider>
)
}
export default MyApp
NextAuth.js handles setting and refreshing session tokens, user verification, OAuth integration with providers like Google and GitHub, and more.
For example, here is how you can enable username/password authentication:
Providers: [
Credentials({
name: 'Credentials',
credentials: {
username: { label: 'Username', type: 'text' },
password: { label: 'Password', type: 'password' }
},
async authorize(credentials) {
// Implement user login here
}
})
]
Overall, NextAuth.js is a great choice for implementing secure, production-ready authentication in Next.js.
So in summary, Supabase and NextAuth.js both provide robust and easy-to-use authentication for Next.js applications. Choose the one that best fits your needs!
How do you protect routes in Next.js 13?
To protect routes that require authentication or authorization in Next.js 13, we can use the App
component to check the user's status and redirect them if needed. This is done by using the useRouter
and useEffect
React hooks.
Here is an example using Supabase for authentication:
import { useRouter } from 'next/router';
import { useEffect } from 'react';
import { useSession } from '@supabase/auth-helpers-react';
export default function App() {
const router = useRouter();
const { session } = useSession();
useEffect(() => {
if (!session && router.pathname !== '/login') {
router.push('/login');
}
}, [session, router]);
return <>{/* children components */}</>;
}
This will check if there is an active user session on each route change. If no session exists, it will redirect the user to the /login
page.
We can build upon this to only allow logged in users to access certain pages by checking session
and router.pathname
in the useEffect
hook.
For example, to protect an /account
route:
useEffect(() => {
if (!session && router.pathname === '/account') {
router.push('/login');
}
}, [session, router]);
This way we ensure that only authenticated users have access to pages or routes that require a login. The possibilities are endless when leveraging Supabase auth with Next.js routers and effects!
sbb-itb-5683811
Setting Up Supabase Server-Side Auth in NextJS
Supabase Auth makes it easy to add user authentication and authorization capabilities to your NextJS applications. With Supabase's auto-generated Auth APIs and secure database, you can get complete user management infrastructure without having to run your own servers.
In this guide, we'll explore integrating Supabase Auth in NextJS using getServerSideProps to check a user's logged-in status on each request before rendering pages. This helps ensure protected routes stay secure.
Initial Supabase Client Configuration
Start by setting up a reusable Supabase Client instance that can be imported anywhere across your NextJS app. This client will manage interactions with your Supabase project.
Here is an example utils/supabaseClient.js
file:
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
export const supabase = createClient(supabaseUrl, supabaseKey)
Make sure to add the Supabase URL and anon public key to your environment variables.
Now the supabase
instance can be imported and used to make authenticated API calls.
Securing Pages with Supabase/SSR
Next, use the Supabase client in getServerSideProps to check if a user session exists on each request.
If no active session is found, redirect the user:
export const getServerSideProps = async ({ req, res }) => {
// Check user is authenticated
const { user } = await supabase.auth.api.getUserByCookie(req)
if (!user) {
return {
redirect: {
destination: '/signin',
permanent: false
}
}
}
// If authenticated, return props
return {
props: {},
}
}
This ensures only logged-in users can access the page.
Server-Side Authentication Example
Here is a full pages/dashboard.js example leveraging Supabase Auth on the server:
import { supabase } from '../utils/supabaseClient'
export const getServerSideProps = async ({ req, res }) => {
// Check user token
const { user } = await supabase.auth.api.getUserByCookie(req)
// Redirect unauthenticated
if (!user) {
return {
redirect: {
destination: '/signin',
permanent: false
}
}
}
// Fetch user data
const { data } = await supabase
.from('profiles')
.select()
.eq('id', user.id)
.single()
return {
props: {
user: data
}
}
}
export default function Dashboard({ user }) {
// Display user data
return (
<div>
<h1>Dashboard</h1>
<p>Hello {user.username}</p>
</div>
)
}
This checks the user cookie on every request, handles redirects, fetches user data from Supabase's database, and displays personalized content in the NextJS page.
By handling authentication logic on the server in getServerSideProps, you can securely render pages for logged in users while keeping anonymous visitors out. Combined with Supabase's auto-generated Auth APIs, adding login functionality is a breeze.
Building Client-Side Auth Flows with Supabase/auth-helpers-react
Integrating authentication in a NextJS app can be tricky, but the Supabase auth helpers for React make it simple. The useUser
hook is the key, providing the user object and session details that enable client-side auth flows.
useUser Hook Overview
The useUser
hook returns the user data and active session information. It automatically refetches the data if the auth state changes.
Here's an example usage:
import { useUser } from '@supabase/auth-helpers-react'
function Profile() {
const { user } = useUser()
return (
<div>
<h2>Profile</h2>
{!user ? (
<p>Loading...</p>
) : (
<p>Hello {user.email}!</p>
)}
</div>
)
}
This allows showing a loading state before rendering profile details only for logged in users.
Conditionally Showing UI Elements
A common use case is conditionally showing UI elements based on auth state. For example, showing a Login button for anonymous users, and a Logout button for authenticated users.
function Header() {
const { user } = useUser()
return (
<header>
<Logo />
{user ? (
<LogoutButton />
) : (
<LoginButton />
)}
</header>
)
}
The user object has properties like user.id
and user.role
that enable granular conditional logic.
Client-Side Auth Flow Example
Here is a full example leveraging useUser
to enable client-side auth in a NextJS app, using Supabase for the backend.
// pages/_app.js
import { SessionContextProvider } from '@supabase/auth-helpers-react'
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_KEY
)
function MyApp({ Component, pageProps }) {
return (
<SessionContextProvider supabaseClient={supabase}>
<Component {...pageProps} />
</SessionContextProvider>
)
}
export default MyApp
This wraps the app with the SessionContextProvider
from @supabase/auth-helpers-react
, passing the Supabase client.
Then we can use the useUser
hook in our pages:
// pages/dashboard.js
import { useUser } from '@supabase/auth-helpers-react'
function Dashboard() {
const { user } = useUser()
return (
<div>
<h2>Dashboard</h2>
{!user ? (
<p>You must be logged in to view this page</p>
) : (
<PrivateData />
)}
</div>
)
}
function PrivateData() {
return <p>Private user data</p>
}
export default Dashboard
Now the dashboard conditionally shows private data only for logged in users.
The useUser
hook manages the auth state automatically across pages, providing user details anywhere they are needed to gate access.
This is just one approach to client-side auth with Supabase and NextJS. There are many possibilities to fit any use case leveraging these tools. Conditional rendering based on auth state is simplified using the useUser
hook from @supabase/auth-helpers-react
.
Managing User Profiles with Supabase NextJS Pages
Supabase makes it easy to manage user profiles in NextJS applications. With Supabase's authentication and database services, you can securely fetch profile data, update user metadata, and implement password recovery flows.
Fetching and Displaying User Details
To display a user's profile data in NextJS pages, you can use Supabase's useUser
hook along with server-side calls. Here is an example pages/profile.js
route that fetches and shows a user's name and email:
import { useUser } from '@supabase/auth-helpers-react'
import { createClient } from '@supabase/supabase-js'
export async function getServerSideProps() {
// Create authenticated Supabase Client
const supabase = createClient()
// Get the user from the server with the auth cookie
const { user } = await supabase.auth.api.getUserByCookie()
// Fetch user data
let { data: profile, error } = await supabase
.from('profiles')
.select(`name, email`)
.eq('id', user.id)
.single()
return {
props: {
user: profile,
},
}
}
export default function Profile({ user }) {
const supabaseUser = useUser()
if (!supabaseUser) {
return <p>Loading...</p>
}
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
)
}
This allows you to securely access the user's data on the server and pass it as props to the page component.
Update User Data
To allow users to update their names, emails, or other custom metadata, you can create forms that update the Supabase user profiles table.
For example, to add an "update profile" form:
// Update profile info
async function updateProfile(data) {
// Get user
const user = supabase.auth.user()
const updates = {
id: user.id,
...data,
updated_at: new Date(),
}
let { error } = await supabase.from('profiles').upsert(updates)
if (error) throw error
alert('Profile updated!')
}
// In UpdateForm component
function UpdateForm() {
async function handleSubmit(e) {
e.preventDefault()
// Call updateProfile method
}
return (
<form onSubmit={handleSubmit}>
{/* name, email, etc. inputs */}
<button>Update profile</button>
</form>
)
}
This allows users to securely modify their stored profile data.
Implementing Password Recovery and Updates
Supabase Auth comes with built-in support for password recovery and updates.
To initiate recovery, call supabase.auth.api.resetPasswordForEmail()
:
async function recoverPassword(email) {
let { error } = await supabase.auth.api.resetPasswordForEmail(email)
if (error) throw error
alert('Check your email for the recovery link!')
}
Then to allow password updates, use the updateUser()
method:
function UpdatePasswordForm() {
async function handleSubmit(password) {
const { error } = await supabase.auth.updateUser({ password })
if (!error) {
alert('Password updated!')
}
}
return (
<form onSubmit={handleSubmit}>
<input name="password" type="password" />
<button>Update Password</button>
</form>
)
}
By integrating these Supabase methods into your auth flows, you can securely manage passwords.
Overall, Supabase's APIs make managing user profiles, custom data, and passwords simple within NextJS apps. The React hooks and server-side methods provide the building blocks for full-featured user dashboards and account management.
Customizing Supabase Auth UI in Your NextJS Project
Override and enhance Supabase's hosted login, register, and password recovery UI screens in your NextJS application.
Implementing Supabase Auth UI Components
Supabase provides a set of pre-built React UI components for quickly adding authentication flows to your app. These include:
Auth.UserContext
- Tracks user state and returns information about the signed-in userAuth.SessionContext
- Lower level context to access the user session objectAuth.AuthContext
- Handles common auth actions likesignIn()
,signOut()
Auth.useUser()
- React hook returning user object
To implement, first install the NPM package:
npm install @supabase/auth-ui-react
Then import and use the components:
import { Auth, ThemeSupa } from '@supabase/auth-ui-react'
export default function Home() {
return (
<Auth.UserContextProvider supabaseClient={supabase}>
<ThemeSupa>
{/* Display login or user UI based on auth state */}
<Auth checkSession>
<Account />
<Login />
</Auth>
</ThemeSupa>
</Auth.UserContextProvider>
)
}
This will handle the auth state and display the appropriate screens. Customize the layout or design by passing props and JSX to components like ThemeSupa
.
Creating Custom Authentication Pages
To build completely custom auth pages while integrating with Supabase for the backend/APIs, use the contexts and hooks:
import { Auth } from '@supabase/auth-ui-react'
function Login() {
const { signIn } = useAuth()
const handleLogin = async (email, password) => {
signIn({ email, password })
}
return (
<form onSubmit={handleLogin}>
{/* Custom login form */}
</form>
)
}
function App() {
return (
<Auth.SessionContextProvider>
<Login />
</Auth.SessionContextProvider>
)
}
This keeps the auth session handling separate while you design fully customized screens.
Tailoring Localization and Theming
To translate text and customize styles/branding:
<ThemeSupa
theme={tailwindTheme}
language={language}
components={{
Button: CustomButton
}}
>
{/* Auth Components */}
</ThemeSupa>
Pass translations, override default CSS with theme
, swap components like Button
, and more.
In summary, Supabase's auth-ui library provides building blocks for fast and secure authentication flows in NextJS. Customize the pre-built screens or create your own using the hooks and contexts!
Leveraging a NextJS Supabase Template for Rapid Development
Jumpstarting development with a pre-built NextJS and Supabase template offers many advantages for accelerating your projects. Templates provide working code examples, configured workflows, and integrated features that allow skipping repetitive setup tasks. However, templates can also introduce unnecessary complexity or force restrictions on your application architecture. Understanding the tradeoffs helps determine if a template aligns to your use case.
Benefits of Using a NextJS Supabase Template
Integrating Supabase's authentication into a NextJS app from scratch requires configuring services across the client and server. Pre-built templates simplify setup by handling this wiring for you with working code for common flows like:
- User signup, login, logout
- Session handling
- Account management
- Password recovery
- OAuth via social platforms
Additional template benefits include:
- Quickstarts Development: Get started faster by cloning a project instead of an empty folder
- Production-Ready Code: Templates often follow best practices for performance, security, and scalability
- Customization Launchpoint: Tweak and extend template features to match your requirements
- Time Savings: Spend more time building app functionality vs routine AuthN/AuthZ tasks
- SEO Optimizations: Templates may integrate popular SEO enhancers like
next-seo
out-of-the-box
Drawbacks of Locking into Templates
While templates accelerate initial progress, they can sometimes create blockers later in development:
- Overengineering: Bulky templates include many unused features that create unnecessary bloat
- Vendor Lock-in: Tied to specific tools that are hard to replace if needs change
- Upgrade Headaches: Breaking changes in dependent packages require fixing template inconsistencies
- Constraint Creativity: Restrict project structure changes due to template coupling
So while tempting to skip straight to coding with a beefy starter kit, consider if it aligns with your application plans or restricts future ideas. Vetting template tradeoffs early helps prevent painful refactors down the road.
Tips for Evaluating NextJS Supabase Templates
When assessing a NextJS Supabase template, check that it:
- Uses the latest stable Supabase and NextJS versions
- Provides clear, idiomatic code examples
- Separates reusable logic into hooks and utils
- Implements React best practices
- Follows compartmentalized folder structure conventions
- Documents key dependencies and configuration
- Highlights customization points for extending
- Offers lightweight and slimmed down installation options
- Stays active with recent releases and updates
Integrating Supabase Auth into a NextJS Application
If skipping the template route, Supabase offers NextJS specific helpers that enable wiring up user management flows directly:
import { createClient } from '@supabase/supabase-js'
import { SessionContextProvider } from '@supabase/auth-helpers-react'
const supabase = createClient(/* supabase url */)
export default function MyApp({ Component, pageProps }) {
return (
<SessionContextProvider supabaseClient={supabase}>
<Component {...pageProps} />
</SessionContextProvider>
)
}
This handles session state, user context, login/logout triggers, and server-side rendering flows. Customizing the integration further supports role-based views, policies, and advanced use cases.
Overall, while templates help fast track basic authentication, take time to evaluate if an integrated example aligns with your plans or causes unnecessary restrictions. Starting minimal then wiring up only required features also keeps your project lean. This lets you iterate without fighting template assumptions down the road.
Key Takeaways and Moving Forward with Supabase Auth in NextJS
Supabase Auth integrates smoothly with NextJS applications using getServerSideProps
for server-side authentication and useUser
hook for client-side auth flows. User management, custom data, and UI customization expand the possibilities further.
Essential Integration Techniques Recap
Here is a quick example using getServerSideProps
for server-side authentication in NextJS with Supabase:
export const getServerSideProps = async ({ req, res }) => {
// Create authenticated Supabase Client
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
)
const {
data: { session },
} = await supabase.auth.getSession()
if (!session)
return { redirect: { destination: '/login' } }
// Pass the user info to the page
return { props: { user: session.user } }
}
And using the useUser
hook for client-side auth with Supabase:
import { useUser } from '@supabase/auth-helpers-react'
function Home() {
const { user } = useUser()
if (!user)
return <Auth />
return <PageContent />
}
These provide the core authentication building blocks when using Supabase Auth in NextJS.
Advanced Authentication Strategies
Some ideas to level up authentication in your Supabase + NextJS application:
- Store custom user data with Supabase profiles
- Enable OAuth via Google, GitHub etc
- Implement granular user permissions
- Set up Single Sign On (SSO) through SAML
- Build custom auth UI with Supabase components
Leveraging these advanced strategies unlocks additional capabilities like access control, social logins, centralized auth, and more.
Supabase Community and Further Resources
- Supabase Auth Docs
- Supabase + NextJS GitHub Repo
- Level Up Tutorials Course on Supabase
- Supabase Discord Community
Use the Supabase docs, example repos, courses, and Discord community for further learning!