The Auth0Provider component wraps your application to provide optimized user data fetching and caching using SWR (Stale-While-Revalidate). It eliminates the initial loading state when using the useUser hook.
Import
import { Auth0Provider } from '@auth0/nextjs-auth0';
Signature
function Auth0Provider({
user,
children
}: {
user?: User;
children: React.ReactNode;
}): JSX.Element
Props
Initial user data to populate the SWR cache. This should be the authenticated user object fetched from the server.When provided, components using useUser() will immediately have access to user data without an initial loading state.
Your application components.
Basic Usage
Wrap your application in the root layout:
import { Auth0Provider } from '@auth0/nextjs-auth0';
import { auth0 } from '@/lib/auth0';
export default async function RootLayout({
children
}: {
children: React.ReactNode;
}) {
const session = await auth0.getSession();
return (
<html lang="en">
<body>
<Auth0Provider user={session?.user}>
{children}
</Auth0Provider>
</body>
</html>
);
}
Now all client components using useUser() will have immediate access to user data:
"use client";
import { useUser } from '@auth0/nextjs-auth0';
export default function Profile() {
const { user } = useUser();
// No loading state needed - user data is immediately available
return (
<div>
<h1>Welcome, {user?.name || 'Guest'}!</h1>
</div>
);
}
Without Auth0Provider
Without Auth0Provider, the useUser hook will show a loading state on initial render:
"use client";
import { useUser } from '@auth0/nextjs-auth0';
export default function Profile() {
const { user, isLoading } = useUser();
// isLoading will be true on first render
if (isLoading) return <div>Loading...</div>;
return <div>Welcome, {user?.name}!</div>;
}
With Auth0Provider
With Auth0Provider, the user data is immediately available:
import { Auth0Provider } from '@auth0/nextjs-auth0';
import { auth0 } from '@/lib/auth0';
export default async function RootLayout({ children }) {
const session = await auth0.getSession();
return (
<html>
<body>
<Auth0Provider user={session?.user}>
{children}
</Auth0Provider>
</body>
</html>
);
}
"use client";
import { useUser } from '@auth0/nextjs-auth0';
export default function Profile() {
const { user } = useUser();
// No loading state - user data is immediately available
return <div>Welcome, {user?.name || 'Guest'}!</div>;
}
Pages Router
For the Pages Router, wrap your _app.tsx:
import type { AppProps } from 'next/app';
import { Auth0Provider } from '@auth0/nextjs-auth0';
function MyApp({ Component, pageProps }: AppProps) {
return (
<Auth0Provider user={pageProps.user}>
<Component {...pageProps} />
</Auth0Provider>
);
}
export default MyApp;
Then fetch the user in getServerSideProps:
import { auth0 } from '@/lib/auth0';
import type { GetServerSideProps } from 'next';
export const getServerSideProps: GetServerSideProps = async (ctx) => {
const session = await auth0.getSession(ctx.req);
return {
props: {
user: session?.user || null
}
};
};
export default function Home() {
return <div>Home Page</div>;
}
How It Works
Auth0Provider uses SWR’s SWRConfig to populate the cache with initial user data:
import { SWRConfig } from 'swr';
export function Auth0Provider({ user, children }) {
return (
<SWRConfig
value={{
fallback: {
[process.env.NEXT_PUBLIC_PROFILE_ROUTE || '/auth/profile']: user
}
}}
>
{children}
</SWRConfig>
);
}
This pre-populates the SWR cache with user data, eliminating the initial fetch when components call useUser().
Custom SWR Configuration
You can combine Auth0Provider with custom SWR configuration:
import { Auth0Provider } from '@auth0/nextjs-auth0';
import { SWRConfig } from 'swr';
import { auth0 } from '@/lib/auth0';
export default async function RootLayout({ children }) {
const session = await auth0.getSession();
return (
<html>
<body>
<SWRConfig
value={{
revalidateOnFocus: false,
revalidateOnReconnect: false,
refreshInterval: 0
}}
>
<Auth0Provider user={session?.user}>
{children}
</Auth0Provider>
</SWRConfig>
</body>
</html>
);
}
Nesting Providers
Auth0Provider can be nested with other providers:
import { Auth0Provider } from '@auth0/nextjs-auth0';
import { ThemeProvider } from '@/components/theme-provider';
import { auth0 } from '@/lib/auth0';
export default async function RootLayout({ children }) {
const session = await auth0.getSession();
return (
<html>
<body>
<ThemeProvider>
<Auth0Provider user={session?.user}>
{children}
</Auth0Provider>
</ThemeProvider>
</body>
</html>
);
}
Handling Unauthenticated Users
When there’s no authenticated user, pass undefined or omit the user prop:
import { Auth0Provider } from '@auth0/nextjs-auth0';
import { auth0 } from '@/lib/auth0';
export default async function RootLayout({ children }) {
const session = await auth0.getSession();
return (
<html>
<body>
<Auth0Provider user={session?.user}>
{children}
</Auth0Provider>
</body>
</html>
);
}
Components using useUser() will correctly show user as null:
"use client";
import { useUser } from '@auth0/nextjs-auth0';
export default function Navigation() {
const { user } = useUser();
return (
<nav>
{user ? (
<a href="/auth/logout">Logout</a>
) : (
<a href="/auth/login">Login</a>
)}
</nav>
);
}
Without Auth0Provider
- Client component renders
useUser() initiates fetch to /auth/profile
- Component shows loading state
- Fetch completes
- Component re-renders with user data
Result: Flash of loading state, extra network request
With Auth0Provider
- Server fetches user during SSR
- User data passed to
Auth0Provider
- SWR cache pre-populated
- Client component renders
useUser() returns cached data immediately
Result: No loading state, no extra network request
TypeScript
import { Auth0Provider } from '@auth0/nextjs-auth0';
import type { User } from '@auth0/nextjs-auth0';
import { auth0 } from '@/lib/auth0';
interface LayoutProps {
children: React.ReactNode;
}
export default async function RootLayout({ children }: LayoutProps) {
const session = await auth0.getSession();
const user: User | undefined = session?.user;
return (
<html>
<body>
<Auth0Provider user={user}>
{children}
</Auth0Provider>
</body>
</html>
);
}
Environment Variables
The provider uses the same profile route as useUser:
# Default: /auth/profile
NEXT_PUBLIC_PROFILE_ROUTE=/api/auth/profile
See Also