Skip to main content
Protect your Next.js pages to ensure only authenticated users can access them. The SDK provides the withPageAuthRequired helper for both server-side and client-side page protection.

Server-Side Protection

Protect pages on the server to redirect unauthenticated users to login before they can access the page content.

App Router

Wrap your Server Component with withPageAuthRequired and provide a returnTo path since Server Components aren’t aware of the page’s URL.
1

Import the auth client

Import your Auth0 client instance:
import { auth0 } from "@/lib/auth0";
2

Wrap your component

Wrap your page component with withPageAuthRequired and specify the returnTo option:
app/profile/page.tsx
import { auth0 } from "@/lib/auth0";

const ProfilePage = auth0.withPageAuthRequired(
  async function Profile() {
    const { user } = await auth0.getSession();
    return <div>Hello {user.name}</div>;
  },
  { returnTo: "/profile" }
);

export default ProfilePage;
The returnTo option is required for App Router pages because Server Components don’t have access to the request URL. This ensures users are redirected back to the correct page after logging in.

Dynamic Routes

For pages with dynamic route parameters, you can use a function for returnTo to preserve the route:
app/posts/[slug]/page.tsx
import { AppRouterPageRouteOpts } from "@auth0/nextjs-auth0/server";
import { auth0 } from "@/lib/auth0";

const PostPage = auth0.withPageAuthRequired(
  async function Post({ params, searchParams }: AppRouterPageRouteOpts) {
    const slug = (await params)?.slug as string;
    const { user } = await auth0.getSession();

    return (
      <div>
        <h1>Post: {slug}</h1>
        <p>Viewing as: {user.name}</p>
      </div>
    );
  },
  {
    async returnTo({ params }) {
      const slug = (await params)?.slug as string;
      return `/posts/${slug}`;
    }
  }
);

export default PostPage;

Pages Router

Use withPageAuthRequired to wrap your getServerSideProps function.
1

Import the auth client

Import your Auth0 client instance:
import { auth0 } from "@/lib/auth0";
2

Create your page component

Define your page component that receives the user prop:
pages/profile.tsx
export default function Profile({ user }) {
  return <div>Hello {user.name}</div>;
}
3

Wrap getServerSideProps

Export getServerSideProps wrapped with withPageAuthRequired:
pages/profile.tsx
import { auth0 } from "@/lib/auth0";

export default function Profile({ user }) {
  return <div>Hello {user.name}</div>;
}

export const getServerSideProps = auth0.withPageAuthRequired();
The SDK automatically adds the user object to your page props.

Custom getServerSideProps

You can pass your own getServerSideProps function, and the SDK will merge your props with the user:
pages/dashboard.tsx
import type { GetServerSideProps, InferGetServerSidePropsType } from "next";
import { auth0 } from "@/lib/auth0";

export default function Dashboard({
  user,
  customData
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
  return (
    <div>
      <h1>Welcome, {user.name}!</h1>
      <p>{customData}</p>
    </div>
  );
}

export const getServerSideProps = auth0.withPageAuthRequired({
  async getServerSideProps(ctx) {
    // Access the session if needed
    const session = await auth0.getSession(ctx.req);

    return {
      props: {
        customData: "Additional data"
      }
    };
  }
});

Custom Return URL

Specify a custom returnTo URL for the login redirect:
pages/protected.tsx
import { auth0 } from "@/lib/auth0";

export default function Protected({ user }) {
  return <div>Protected content for {user.name}</div>;
}

export const getServerSideProps = auth0.withPageAuthRequired({
  returnTo: "/protected"
});

Client-Side Protection

Protect client-rendered pages to redirect users on the client side. This is useful for pages that don’t need SEO or where you want client-side rendering.
1

Add 'use client' directive

Mark your component as a client component:
"use client";
2

Import and wrap your component

Import withPageAuthRequired from the client package and wrap your component:
app/profile/page.tsx
"use client";

import { withPageAuthRequired } from "@auth0/nextjs-auth0/client";

export default withPageAuthRequired(function Profile({ user }) {
  return <div>Hello, {user.name}!</div>;
});
Client-side protection only works after the page loads in the browser. The page content may briefly flash before redirecting unauthenticated users. For SEO-sensitive pages, use server-side protection instead.

With Loading State

The withPageAuthRequired HOC passes a user prop and handles loading states automatically:
"use client";

import { withPageAuthRequired } from "@auth0/nextjs-auth0/client";

function Profile({ user }) {
  return (
    <div>
      <h1>Profile</h1>
      <pre>{JSON.stringify(user, null, 2)}</pre>
    </div>
  );
}

export default withPageAuthRequired(Profile, {
  onRedirecting: () => <div>Redirecting to login...</div>,
  onError: (error) => <div>Error: {error.message}</div>
});

Comparison: Server vs Client

FeatureServer-SideClient-Side
SEO✅ Crawlable❌ Not crawlable
Initial LoadProtected from startBrief flash possible
Use CasePublic-facing pagesAdmin dashboards
RouterApp Router, Pages RouterApp Router only
PerformanceFaster initial loadSlower (JS required)

Best Practices

  • Use server-side protection for pages that need SEO or contain sensitive data
  • Use client-side protection for internal dashboards or admin panels
  • Always specify returnTo in App Router to ensure users return to the correct page after login
  • Keep returnTo URLs registered in your Auth0 Dashboard under Allowed Callback URLs

Troubleshooting

Users not redirected after login

Ensure the returnTo URL is registered in your Auth0 Application settings:
  1. Go to the Auth0 Dashboard
  2. Navigate to Applications > Your Application
  3. Add your URL to Allowed Callback URLs

Server Component errors

If you see “Server Component” errors with App Router:
  • Ensure you’re providing the returnTo option
  • Don’t use redirect() manually; let withPageAuthRequired handle it

Pages Router props not merged

If custom props aren’t showing up:
  • Make sure your getServerSideProps returns a props object
  • Don’t return redirect or notFound from your custom function; return props only

Build docs developers (and LLMs) love