Authorization Patterns
Authorization failures are a special in-between state. Unlike validation errors that users can fix, auth errors need clear messaging and a path back to safety. Next.js 16 introduces unauthorized() and forbidden() functions that trigger dedicated pages.
In Server Components and Queries
Call unauthorized() to immediately render unauthorized.tsx:
import { unauthorized } from 'next/navigation';
export default function DashboardPage() {
if (!canManagePosts()) {
unauthorized();
}
return <Dashboard />;
}Or in data queries that require authorization:
export const getPosts = cache(async (filter, sort) => {
if (!canManagePosts()) {
unauthorized();
}
return await prisma.post.findMany({ ... });
});Both throw—unauthorized() never returns.
The unauthorized.tsx Page
Create a dedicated page that matches your app's design:
import Link from 'next/link';
export default function Unauthorized() {
return (
<StatusCard
icon={LockKeyhole}
title="Unauthorized"
description="You don't have permission to access this page."
>
<Link href="/">Back to Blog</Link>
</StatusCard>
);
}unauthorized() vs forbidden()
| Function | HTTP Status | Use When |
|---|---|---|
unauthorized() | 401 | User not authenticated |
forbidden() | 403 | User authenticated but lacks permission |
Both render their respective .tsx files and stop execution.