This guide will get you from zero to a working authentication flow in your Next.js application.
Prerequisites
Before you begin, make sure you have:
Node.js 20 LTS or newer installed
A Next.js application (14.2.35 or newer)
An Auth0 account (free tier works)
Step 1: Install the SDK
Install the Auth0 Next.js SDK using your preferred package manager:
npm install @auth0/nextjs-auth0
Create a .env.local file in your project root and add the following variables:
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_CLIENT_ID=your_client_id
AUTH0_CLIENT_SECRET=your_client_secret
AUTH0_SECRET=use_openssl_rand_hex_32_to_generate_this
APP_BASE_URL=http://localhost:3000
Get Auth0 credentials
Go to the Auth0 Dashboard
Create a new application or select an existing one
Choose Regular Web Application as the application type
Copy the Domain , Client ID , and Client Secret from the application settings
Generate AUTH0_SECRET
Generate a random 32-byte hex string for encrypting session cookies: Copy the output and use it as your AUTH0_SECRET.
Configure callback URLs
In your Auth0 application settings, add the following URLs:
Allowed Callback URLs : http://localhost:3000/auth/callback
Allowed Logout URLs : http://localhost:3000
For production deployments, update APP_BASE_URL to your production domain and register the production callback URLs in Auth0.
Step 3: Create the Auth0 Client
Create a file lib/auth0.ts (or lib/auth0.js) in your project:
import { Auth0Client } from '@auth0/nextjs-auth0/server' ;
export const auth0 = new Auth0Client ();
This creates an Auth0 client instance that will be used throughout your application.
Step 4: Add Authentication Middleware
Authentication requests are intercepted at the network boundary. Choose the setup for your Next.js version:
Create a middleware.ts file in the root of your project: import type { NextRequest } from 'next/server' ;
import { auth0 } from './lib/auth0' ;
export async function middleware ( request : NextRequest ) {
return await auth0 . middleware ( request );
}
export const config = {
matcher: [
/*
* Match all request paths except for:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico, sitemap.xml, robots.txt (metadata files)
*/
'/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)' ,
],
};
If you’re using a src/ directory, place the middleware.ts file inside the src/ directory.
Create a proxy.ts file in the root of your project: import { auth0 } from './lib/auth0' ;
export async function proxy ( request : Request ) {
return await auth0 . middleware ( request );
}
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)' ,
],
};
Next.js 16 uses proxy.ts instead of middleware.ts. The proxy layer executes earlier in the routing pipeline and the Edge runtime applies stricter validation.
The broad middleware matcher is essential for rolling sessions and security features. See the Session Configuration guide for more details.
Step 5: Add Login and Logout
Update your home page to include login and logout functionality:
import { auth0 } from '@/lib/auth0' ;
export default async function Home () {
const session = await auth0 . getSession ();
if ( ! session ) {
return (
< main className = "flex min-h-screen flex-col items-center justify-center p-24" >
< h1 className = "text-4xl font-bold mb-8" > Welcome to My App </ h1 >
< div className = "flex gap-4" >
< a
href = "/auth/login?screen_hint=signup"
className = "px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
>
Sign up
</ a >
< a
href = "/auth/login"
className = "px-6 py-3 bg-gray-800 text-white rounded-lg hover:bg-gray-900"
>
Log in
</ a >
</ div >
</ main >
);
}
return (
< main className = "flex min-h-screen flex-col items-center justify-center p-24" >
< h1 className = "text-4xl font-bold mb-4" > Welcome , { session . user . name } !</ h1 >
< p className = "text-gray-600 mb-8" > {session.user. email } </ p >
< a
href = "/auth/logout"
className = "px-6 py-3 bg-red-600 text-white rounded-lg hover:bg-red-700"
>
Log out
</ a >
</ main >
);
}
import { auth0 } from '@/lib/auth0' ;
import { GetServerSideProps } from 'next' ;
export default function Home ({ user } : { user : any }) {
if ( ! user ) {
return (
< main className = "flex min-h-screen flex-col items-center justify-center p-24" >
< h1 className = "text-4xl font-bold mb-8" > Welcome to My App </ h1 >
< div className = "flex gap-4" >
< a
href = "/auth/login?screen_hint=signup"
className = "px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
>
Sign up
</ a >
< a
href = "/auth/login"
className = "px-6 py-3 bg-gray-800 text-white rounded-lg hover:bg-gray-900"
>
Log in
</ a >
</ div >
</ main >
);
}
return (
< main className = "flex min-h-screen flex-col items-center justify-center p-24" >
< h1 className = "text-4xl font-bold mb-4" > Welcome , { user . name } !</ h1 >
< p className = "text-gray-600 mb-8" > {user. email } </ p >
< a
href = "/auth/logout"
className = "px-6 py-3 bg-red-600 text-white rounded-lg hover:bg-red-700"
>
Log out
</ a >
</ main >
);
}
export const getServerSideProps : GetServerSideProps = async ({ req , res }) => {
const session = await auth0 . getSession ( req , res );
return {
props: {
user: session ?. user || null ,
},
};
};
Always use <a> tags for auth routes instead of Next.js <Link> components to ensure proper server-side navigation.
Step 6: Test Your Application
Start the development server
Your app should now be running at http://localhost:3000.
Test the login flow
Click Log in or Sign up
You’ll be redirected to Auth0’s login page
Enter your credentials or sign up
You’ll be redirected back to your app, now logged in
Test the logout flow
Click Log out to sign out. You’ll be logged out of Auth0 and redirected back to your app.
Now that authentication is working, you can access user information throughout your app:
In Server Components (App Router)
import { auth0 } from '@/lib/auth0' ;
export default async function Profile () {
const session = await auth0 . getSession ();
if ( ! session ) {
return < div > Please log in </ div > ;
}
return (
< div >
< h1 >{session.user. name } </ h1 >
< p >{session.user. email } </ p >
< img src = {session.user. picture } alt = "Profile" />
</ div >
);
}
In Client Components
First, wrap your app with the Auth0Provider:
import { Auth0Provider } from '@auth0/nextjs-auth0/client' ;
export default function RootLayout ({ children } : { children : React . ReactNode }) {
return (
< html lang = "en" >
< body >
< Auth0Provider >
{ children }
</ Auth0Provider >
</ body >
</ html >
);
}
Then use the useUser hook in client components:
'use client' ;
import { useUser } from '@auth0/nextjs-auth0/client' ;
export default function Profile () {
const { user , error , isLoading } = useUser ();
if ( isLoading ) return < div > Loading ...</ div > ;
if ( error ) return < div > Error : {error. message } </ div > ;
if ( ! user ) return < a href = "/auth/login" > Log in </ a > ;
return (
< div >
< h1 >{user. name } </ h1 >
< p >{user. email } </ p >
< img src = {user. picture } alt = "Profile" />
</ div >
);
}
Next Steps
You now have a fully working authentication system! Here are some next steps:
Protect Pages Learn how to protect entire pages and routes
Get Access Tokens Call external APIs with access tokens
Customize Sessions Configure session duration and storage
Advanced Features Explore DPoP, MFA, and MRRT
Troubleshooting
This usually happens when cookies are blocked or the AUTH0_SECRET has changed. Make sure:
Cookies are enabled in your browser
The AUTH0_SECRET matches across restarts
You’re not mixing HTTP and HTTPS during development
Ensure your callback URL is registered in Auth0:
Go to your Auth0 application settings
Add http://localhost:3000/auth/callback to Allowed Callback URLs
For production, add your production callback URL
Check that your middleware is properly configured and the matcher pattern is correct. The middleware must run on every request for rolling sessions to work.
Need more help? Check the Troubleshooting guide.