The withPageAuthRequired higher-order component (HOC) protects client-side rendered pages by automatically redirecting unauthenticated users to the login page.
Import
import { withPageAuthRequired } from '@auth0/nextjs-auth0';
Signature
function withPageAuthRequired<P extends object>(
Component: ComponentType<P & UserProps>,
options?: WithPageAuthRequiredOptions
): React.FC<P>
Parameters
Component
ComponentType<P & UserProps>
required
The component to protect. The wrapped component will receive a user prop containing the authenticated user object.
options
WithPageAuthRequiredOptions
Configuration options for the HOC.The path to return the user to after login. If not specified, the user will be returned to the current page.
Custom component to render while redirecting to login. Defaults to an empty fragment.
options.onError
(error: Error) => JSX.Element
Custom component to render when there’s an error fetching user data. Defaults to an empty fragment.
Return Value
Returns a new React functional component that:
- Checks for user authentication
- Redirects to login if not authenticated
- Passes the
user prop to the wrapped component
- Handles loading and error states
Basic Usage
"use client";
import { withPageAuthRequired } from '@auth0/nextjs-auth0';
function Dashboard({ user }) {
return (
<div>
<h1>Dashboard</h1>
<p>Welcome, {user.name}!</p>
<img src={user.picture} alt={user.name} />
</div>
);
}
export default withPageAuthRequired(Dashboard);
Custom Return Path
Specify where to redirect after login:
"use client";
import { withPageAuthRequired } from '@auth0/nextjs-auth0';
function Profile({ user }) {
return (
<div>
<h1>Profile</h1>
<p>{user.email}</p>
</div>
);
}
export default withPageAuthRequired(Profile, {
returnTo: '/profile'
});
Custom Loading State
Show a custom component while redirecting to login:
"use client";
import { withPageAuthRequired } from '@auth0/nextjs-auth0';
function Settings({ user }) {
return (
<div>
<h1>Settings</h1>
<p>User ID: {user.sub}</p>
</div>
);
}
export default withPageAuthRequired(Settings, {
onRedirecting: () => (
<div className="loading-spinner">
<p>Redirecting to login...</p>
</div>
)
});
Custom Error Handling
Handle errors when fetching user data:
"use client";
import { withPageAuthRequired } from '@auth0/nextjs-auth0';
function Admin({ user }) {
return (
<div>
<h1>Admin Panel</h1>
<p>Logged in as: {user.email}</p>
</div>
);
}
export default withPageAuthRequired(Admin, {
onError: (error) => (
<div className="error">
<h1>Authentication Error</h1>
<p>{error.message}</p>
<a href="/auth/login">Try Again</a>
</div>
)
});
Complete Example
"use client";
import { withPageAuthRequired } from '@auth0/nextjs-auth0';
function ProtectedPage({ user }) {
return (
<div>
<h1>Protected Content</h1>
<div className="user-info">
<img src={user.picture} alt={user.name} />
<div>
<p><strong>Name:</strong> {user.name}</p>
<p><strong>Email:</strong> {user.email}</p>
<p><strong>User ID:</strong> {user.sub}</p>
</div>
</div>
<a href="/auth/logout">Logout</a>
</div>
);
}
export default withPageAuthRequired(ProtectedPage, {
returnTo: '/protected',
onRedirecting: () => (
<div className="flex items-center justify-center min-h-screen">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-gray-900" />
</div>
),
onError: (error) => (
<div className="error-container">
<h1>Oops! Something went wrong</h1>
<p>{error.message}</p>
<button onClick={() => window.location.reload()}>
Retry
</button>
</div>
)
});
With TypeScript
"use client";
import { withPageAuthRequired } from '@auth0/nextjs-auth0';
import type { User } from '@auth0/nextjs-auth0';
interface DashboardProps {
customProp: string;
}
function Dashboard({ user, customProp }: DashboardProps & { user: User }) {
return (
<div>
<h1>Dashboard</h1>
<p>Welcome, {user.name}!</p>
<p>Custom: {customProp}</p>
</div>
);
}
export default withPageAuthRequired(Dashboard);
Passing Additional Props
"use client";
import { withPageAuthRequired } from '@auth0/nextjs-auth0';
function DataViewer({ user, dataSource }) {
return (
<div>
<h1>Data from {dataSource}</h1>
<p>Viewing as: {user.email}</p>
</div>
);
}
const ProtectedDataViewer = withPageAuthRequired(DataViewer);
export default function Page() {
return <ProtectedDataViewer dataSource="Analytics API" />;
}
How It Works
The HOC performs the following steps:
- Uses
useUser hook to fetch user data
- Checks authentication state:
- If
isLoading is true, renders onRedirecting component
- If
error exists, renders onError component
- If no
user and not loading, redirects to login
- Constructs login URL with
returnTo parameter
- Redirects using
window.location.assign()
- Passes
user prop to wrapped component once authenticated
Redirect Flow
When an unauthenticated user visits a protected page:
- User visits
/dashboard
withPageAuthRequired detects no user
- Redirects to
/auth/login?returnTo=/dashboard
- User completes authentication
- Auth0 redirects back to
/dashboard
- User sees the protected content
Client vs Server Protection
| Feature | Client (CSR) | Server (SSR) |
|---|
| Rendering | Client-side | Server-side |
| Protection | After page load | Before page load |
| Loading Flash | May show loading state | No loading state |
| SEO | Not crawlable | Crawlable (if public) |
| Use Case | Interactive client components | SEO-friendly pages |
When to Use Client Protection
- Client-side rendered (CSR) pages
- Pages with heavy client-side interactions
- Single-page application (SPA) patterns
- When you need custom loading/error states
When to Use Server Protection
Use the server-side version for:
- Server-side rendered (SSR) pages
- Better SEO
- Faster initial page loads
- No flash of unauthenticated content
Environment Variables
The HOC uses the login route for redirects:
# Default: /auth/login
NEXT_PUBLIC_LOGIN_ROUTE=/api/auth/login
Common Patterns
Role-Based Access Control
"use client";
import { withPageAuthRequired } from '@auth0/nextjs-auth0';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';
function AdminPanel({ user }) {
const router = useRouter();
useEffect(() => {
// Check if user has admin role
const roles = user['https://example.com/roles'] || [];
if (!roles.includes('admin')) {
router.push('/unauthorized');
}
}, [user, router]);
return (
<div>
<h1>Admin Panel</h1>
<p>Welcome, admin {user.name}!</p>
</div>
);
}
export default withPageAuthRequired(AdminPanel);
Organization Check
"use client";
import { withPageAuthRequired } from '@auth0/nextjs-auth0';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';
function OrgDashboard({ user }) {
const router = useRouter();
useEffect(() => {
// Ensure user belongs to an organization
if (!user.org_id) {
router.push('/join-organization');
}
}, [user, router]);
return (
<div>
<h1>Organization Dashboard</h1>
<p>Organization ID: {user.org_id}</p>
</div>
);
}
export default withPageAuthRequired(OrgDashboard);
See Also