Protect content from unauthenticated users
This guide demonstrates how to protect pages, Route Handlers, and Server Actions from unauthenticated users in your Next.js application.
To protect your application, every resource that reads or mutates protected data needs its own check. In a Next.js app, this means protecting:
- Server Components: Layouts and pages
- Route Handlers: Your internal Next.js API endpoints
- Server Actions: These run as API endpoints, so protect them like any other handler.
- External API endpoints your app calls: These endpoints must enforce their own authentication.
Server-side
auth()
Use auth.protect()isAuthenticated yourself if you want more control over the response.
The following examples demonstrate both methods.
Protect a page
import { auth } from '@clerk/nextjs/server'
export default async function Page() {
// Redirects to the sign-in route if the user is not signed in
await auth.protect()
return <h1>Hello world</h1>
}import { auth } from '@clerk/nextjs/server'
export default async function Page() {
const { isAuthenticated, redirectToSignIn } = await auth()
if (!isAuthenticated) {
// Add logic to handle the unauthenticated user
// This example uses the `redirectToSignIn()` method to redirect the user to the sign-in page
return redirectToSignIn()
}
return <h1>Hello world</h1>
}Protect a layout
You can run an auth check in a layout the same way as in a page, and you should if the layout itself reads privileged data (for example, when prefetching). But a layout check alone isn't enough: layouts don't re-render on client-side navigation, so the session isn't re-checked on every route change. Protect each page (and every other resource that reads or mutates data) directly, and treat a layout check as an addition, not a replacement. For more information, see the Next.js docs.
Protect a Route Handler
For non-document requests, such as API requests, auth.protect()
- A
404error for unauthenticated requests with session token type. - A
401error for unauthenticated requests with machine token types.
import { auth } from '@clerk/nextjs/server'
export const GET = async () => {
// Returns a `404` error for unauthenticated requests
const { userId } = await auth.protect()
return Response.json({ userId })
}import { auth } from '@clerk/nextjs/server'
export const GET = async () => {
const { isAuthenticated, userId } = await auth()
if (!isAuthenticated) {
// Add logic to handle the unauthenticated user
// This example returns an 'Unauthorized' error with a 401 status code
return Response.json({ error: 'Unauthorized' }, { status: 401 })
}
return Response.json({ userId })
}Protect a Server Action
Server Actions can be called from any Client Component, so verify the user inside the action itself, before running any logic that depends on them being signed in.
Inside a Server Action, auth.protect()401 error instead. To handle the unauthenticated case yourself, use auth().
'use server'
import { auth } from '@clerk/nextjs/server'
export async function createPost(formData: FormData) {
// Returns a 401 error if the user is not signed in
const { userId } = await auth.protect()
// Add your Server Action logic using the `userId`
}'use server'
import { auth } from '@clerk/nextjs/server'
export async function createPost(formData: FormData) {
const { isAuthenticated, userId } = await auth()
if (!isAuthenticated) {
// Add logic to handle the unauthenticated user:
throw new Error('You must be signed in to create a post.')
}
// Add your Server Action logic using the `userId`
}Client-side
On the client, you can read the isSignedIn property from the useAuth() or useUser() hook to conditionally render UI based on whether the user is signed in.
'use client'
import { useAuth } from '@clerk/nextjs'
export default function Page() {
const { isLoaded, isSignedIn } = useAuth()
// Handle loading state
if (!isLoaded) return <h1>Loading...</h1>
if (!isSignedIn) {
// Add logic to handle the unauthenticated user
// This example renders a UI but you could also redirect to the sign-in page instead
return <h1>You must be signed in to view this page</h1>
}
return <h1>Hello world</h1>
}'use client'
import { useUser } from '@clerk/nextjs'
export default function Page() {
const { isSignedIn, isLoaded } = useUser()
// Handle loading state
if (!isLoaded) return <h1>Loading...</h1>
if (!isSignedIn) {
// Add logic to handle the unauthenticated user
// This example renders a UI but you could also redirect to the sign-in page instead
return <h1>You must be signed in to view this page</h1>
}
return <h1>Hello world</h1>
}Feedback
Last updated on