From 712d7c9eab896a929df69b240abf1c4511324f88 Mon Sep 17 00:00:00 2001
From: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com>
Date: Mon, 25 Nov 2024 07:03:41 -0800
Subject: [PATCH] 15.1 docs: `forbidden`, `unauthorized`, and `authInterrupts`
(#73039)
**Do not merge until https://github.com/vercel/next.js/pull/72785 lands
in canary.**
Closes:
-
https://linear.app/vercel/issue/DOC-3820/[unstable]-forbidden-and-forbiddenjs
-
https://linear.app/vercel/issue/DOC-3849/[unstable]-unauthorized-and-unauthorizedjs
-
https://linear.app/vercel/issue/DOC-3860/[experimental]-authinterrupts-config-option
---
.../03-file-conventions/forbidden.mdx | 50 ++++
.../03-file-conventions/not-found.mdx | 10 +-
.../03-file-conventions/unauthorized.mdx | 114 +++++++++
.../04-functions/forbidden.mdx | 172 +++++++++++++
.../04-functions/unauthorized.mdx | 230 ++++++++++++++++++
.../01-next-config-js/authInterrupts.mdx | 33 +++
6 files changed, 606 insertions(+), 3 deletions(-)
create mode 100644 docs/01-app/03-api-reference/03-file-conventions/forbidden.mdx
create mode 100644 docs/01-app/03-api-reference/03-file-conventions/unauthorized.mdx
create mode 100644 docs/01-app/03-api-reference/04-functions/forbidden.mdx
create mode 100644 docs/01-app/03-api-reference/04-functions/unauthorized.mdx
create mode 100644 docs/01-app/03-api-reference/05-config/01-next-config-js/authInterrupts.mdx
diff --git a/docs/01-app/03-api-reference/03-file-conventions/forbidden.mdx b/docs/01-app/03-api-reference/03-file-conventions/forbidden.mdx
new file mode 100644
index 0000000000000..de4be46954652
--- /dev/null
+++ b/docs/01-app/03-api-reference/03-file-conventions/forbidden.mdx
@@ -0,0 +1,50 @@
+---
+title: forbidden.js
+description: API reference for the forbidden.js special file.
+related:
+ links:
+ - app/api-reference/functions/forbidden
+version: canary
+---
+
+The **forbidden** file is used to render UI when the [`forbidden`](/docs/app/api-reference/functions/forbidden) function is invoked during authentication. Along with allowing you to customize the UI, Next.js will return a `403` status code.
+
+```tsx filename="app/forbidden.tsx" switcher
+import Link from 'next/link'
+
+export default function Forbidden() {
+ return (
+
+
Forbidden
+
You are not authorized to access this resource.
+ Return Home
+
+ )
+}
+```
+
+```jsx filename="app/forbidden.jsx" switcher
+import Link from 'next/link'
+
+export default function Forbidden() {
+ return (
+
+
Forbidden
+
You are not authorized to access this resource.
+ Return Home
+
+ )
+}
+```
+
+## Reference
+
+### Props
+
+`forbidden.js` components do not accept any props.
+
+## Version History
+
+| Version | Changes |
+| --------- | -------------------------- |
+| `v15.1.0` | `forbidden.js` introduced. |
diff --git a/docs/01-app/03-api-reference/03-file-conventions/not-found.mdx b/docs/01-app/03-api-reference/03-file-conventions/not-found.mdx
index dd23e63c4f06d..a5b2aae9db1a6 100644
--- a/docs/01-app/03-api-reference/03-file-conventions/not-found.mdx
+++ b/docs/01-app/03-api-reference/03-file-conventions/not-found.mdx
@@ -33,13 +33,17 @@ export default function NotFound() {
}
```
-> **Good to know**: In addition to catching expected `notFound()` errors, the root `app/not-found.js` file also handles any unmatched URLs for your whole application. This means users that visit a URL that is not handled by your app will be shown the UI exported by the `app/not-found.js` file.
+## Reference
-## Props
+### Props
`not-found.js` components do not accept any props.
-## Data Fetching
+> **Good to know**: In addition to catching expected `notFound()` errors, the root `app/not-found.js` file also handles any unmatched URLs for your whole application. This means users that visit a URL that is not handled by your app will be shown the UI exported by the `app/not-found.js` file.
+
+## Examples
+
+### Data Fetching
By default, `not-found` is a Server Component. You can mark it as `async` to fetch and display data:
diff --git a/docs/01-app/03-api-reference/03-file-conventions/unauthorized.mdx b/docs/01-app/03-api-reference/03-file-conventions/unauthorized.mdx
new file mode 100644
index 0000000000000..dda9f82ea463a
--- /dev/null
+++ b/docs/01-app/03-api-reference/03-file-conventions/unauthorized.mdx
@@ -0,0 +1,114 @@
+---
+title: unauthorized.js
+description: API reference for the unauthorized.js special file.
+related:
+ links:
+ - app/api-reference/functions/unauthorized
+version: canary
+---
+
+The **unauthorized** file is used to render UI when the [`unauthorized`](/docs/app/api-reference/functions/unauthorized) function is invoked during authentication. Along with allowing you to customize the UI, Next.js will return a `401` status code.
+
+```tsx filename="app/unauthorized.tsx" switcher
+import Login from '@/app/components/Login'
+
+export default function Unauthorized() {
+ return (
+
+
+
+
+ )
+}
+```
+
+## Version History
+
+| Version | Changes |
+| --------- | ----------------------------- |
+| `v15.1.0` | `unauthorized.js` introduced. |
diff --git a/docs/01-app/03-api-reference/04-functions/forbidden.mdx b/docs/01-app/03-api-reference/04-functions/forbidden.mdx
new file mode 100644
index 0000000000000..1bb8fc118fc43
--- /dev/null
+++ b/docs/01-app/03-api-reference/04-functions/forbidden.mdx
@@ -0,0 +1,172 @@
+---
+title: forbidden
+description: API Reference for the forbidden function.
+version: canary
+related:
+ links:
+ - app/api-reference/file-conventions/forbidden
+---
+
+The `forbidden` function throws an error that renders a Next.js 403 error page. It is useful for handling authorization errors in your application. You can customize the UI using the [`forbidden.js` file](/docs/app/api-reference/file-conventions/forbidden).
+
+To start using `forbidden`, enable the experimental [`authInterrupts`](/docs/app/api-reference/config/next-config-js/authInterrupts) configuration option in your `next.config.js` file:
+
+```ts filename="next.config.ts" switcher
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {
+ experimental: {
+ authInterrupts: true,
+ },
+}
+
+export default nextConfig
+```
+
+```js filename="next.config.js" switcher
+module.exports = {
+ experimental: {
+ authInterrupts: true,
+ },
+}
+```
+
+`forbidden` can be used in [Server Components](/docs/app/building-your-application/rendering/server-components), [Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations), and [Route Handlers](/docs/app/building-your-application/routing/route-handlers).
+
+```tsx filename="app/auth/route.tsx" switcher
+import { verifySession } from '@/app/lib/dal'
+import { forbidden } from 'next/navigation'
+
+export default async function AdminPage() {
+ const session = await verifySession()
+
+ // Check if the user has the 'admin' role
+ if (session.role !== 'admin') {
+ forbidden()
+ }
+
+ // Render the admin page for authorized users
+ return <>>
+}
+```
+
+```jsx filename="app/auth/route.js" switcher
+import { verifySession } from '@/app/lib/dal'
+import { forbidden } from 'next/navigation'
+
+export default async function AdminPage() {
+ const session = await verifySession()
+
+ // Check if the user has the 'admin' role
+ if (session.role !== 'admin') {
+ forbidden()
+ }
+
+ // Render the admin page for authorized users
+ return <>>
+}
+```
+
+## Good to know
+
+- The `forbidden` function cannot be called in the [root layout](/docs/app/building-your-application/routing/layouts-and-templates#root-layout-required).
+
+## Examples
+
+### Role-based route protection
+
+You can use the `forbidden` function to restrict access to certain routes based on user roles. This ensures that users who are authenticated but lack the required permissions cannot access the route.
+
+```tsx filename="app/admin/page.tsx" switcher
+import { verifySession } from '@/app/lib/dal'
+import { forbidden } from 'next/navigation'
+
+export default async function AdminPage() {
+ const session = await verifySession()
+
+ // Check if the user has the 'admin' role
+ if (session.role !== 'admin') {
+ forbidden()
+ }
+
+ // Render the admin page for authorized users
+ return (
+
+
Admin Dashboard
+
Welcome, {session.user.name}!
+
+ )
+}
+```
+
+```jsx filename="app/admin/page.js" switcher
+import { verifySession } from '@/app/lib/dal'
+import { forbidden } from 'next/navigation'
+
+export default async function AdminPage() {
+ const session = await verifySession()
+
+ // Check if the user has the 'admin' role
+ if (session.role !== 'admin') {
+ forbidden()
+ }
+
+ // Render the admin page for authorized users
+ return (
+
+
Admin Dashboard
+
Welcome, {session.user.name}!
+
+ )
+}
+```
+
+### Mutations with Server Actions
+
+When implementing mutations in Server Actions, you can use `forbidden` to only allow users with a specific role to update sensitive data.
+
+```tsx filename="app/auth/route.tsx" switcher
+'use server'
+
+import { verifySession } from '@/app/lib/dal'
+import { forbidden } from 'next/navigation'
+import db from '@/app/lib/db'
+
+export async function updateRole(formData: FormData) {
+ const session = await verifySession()
+
+ // Ensure only admins can update roles
+ if (session.role !== 'admin') {
+ forbidden()
+ }
+
+ // Perform the role update for authorized users
+ // ...
+}
+```
+
+```jsx filename="app/auth/route.js" switcher
+'use server'
+
+import { verifySession } from '@/app/lib/dal'
+import { forbidden } from 'next/navigation'
+import db from '@/app/lib/db'
+
+export async function updateRole(formData) {
+ const session = await verifySession()
+
+ // Ensure only admins can update roles
+ if (session.role !== 'admin') {
+ forbidden()
+ }
+
+ // Perform the role update for authorized users
+ // ...
+}
+```
+
+## Version History
+
+| Version | Changes |
+| --------- | ----------------------- |
+| `v15.1.0` | `forbidden` introduced. |
diff --git a/docs/01-app/03-api-reference/04-functions/unauthorized.mdx b/docs/01-app/03-api-reference/04-functions/unauthorized.mdx
new file mode 100644
index 0000000000000..5422f5458abc7
--- /dev/null
+++ b/docs/01-app/03-api-reference/04-functions/unauthorized.mdx
@@ -0,0 +1,230 @@
+---
+title: unauthorized
+description: API Reference for the unauthorized function.
+version: canary
+related:
+ links:
+ - app/api-reference/file-conventions/unauthorized
+---
+
+The `unauthorized` function throws an error that renders a Next.js 401 error page. It is useful for handling authorization errors in your application. You can customize the UI using the [`unauthorized.js` file](/docs/app/api-reference/file-conventions/unauthorized).
+
+To start using `unauthorized`, enable the experimental [`authInterrupts`](/docs/app/api-reference/config/next-config-js/authInterrupts) configuration option in your `next.config.js` file:
+
+```ts filename="next.config.ts" switcher
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {
+ experimental: {
+ authInterrupts: true,
+ },
+}
+
+export default nextConfig
+```
+
+```js filename="next.config.js" switcher
+module.exports = {
+ experimental: {
+ authInterrupts: true,
+ },
+}
+```
+
+`unauthorized` can be invoked in [Server Components](/docs/app/building-your-application/rendering/server-components), [Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations), and [Route Handlers](/docs/app/building-your-application/routing/route-handlers).
+
+```tsx filename="app/dashboard/page.tsx" switcher
+import { verifySession } from '@/app/lib/dal'
+import { unauthorized } from 'next/navigation'
+
+export default async function DashboardPage() {
+ const session = await verifySession()
+
+ if (!session) {
+ unauthorized()
+ }
+
+ // Render the dashboard for authenticated users
+ return (
+
+
Welcome to the Dashboard
+
Hi, {session.user.name}.
+
+ )
+}
+```
+
+```jsx filename="app/dashboard/page.js" switcher
+import { verifySession } from '@/app/lib/dal'
+import { unauthorized } from 'next/navigation'
+
+export default async function DashboardPage() {
+ const session = await verifySession()
+
+ if (!session) {
+ unauthorized()
+ }
+
+ // Render the dashboard for authenticated users
+ return (
+
+
Welcome to the Dashboard
+
Hi, {session.user.name}.
+
+ )
+}
+```
+
+## Examples
+
+### Displaying login UI to unauthenticated users
+
+You can use `unauthorized` function to display the `unauthorized.js` file with a login UI.
+
+```tsx filename="app/dashboard/page.tsx" switcher
+import { verifySession } from '@/app/lib/dal'
+import { unauthorized } from 'next/navigation'
+
+export default async function DashboardPage() {
+ const session = await verifySession()
+
+ if (!session) {
+ unauthorized()
+ }
+
+ return
+
+
+ )
+}
+```
+
+### Mutations with Server Actions
+
+You can invoke `unauthorized` in Server Actions to ensure only authenticated users can perform specific mutations.
+
+```ts filename="app/actions/update-profile.ts" switcher
+'use server'
+
+import { verifySession } from '@/app/lib/dal'
+import { unauthorized } from 'next/navigation'
+import db from '@/app/lib/db'
+
+export async function updateProfile(data: FormData) {
+ const session = await verifySession()
+
+ // If the user is not authenticated, return a 401
+ if (!session) {
+ unauthorized()
+ }
+
+ // Proceed with mutation
+ // ...
+}
+```
+
+```js filename="app/actions/update-profile.js" switcher
+'use server'
+
+import { verifySession } from '@/app/lib/dal'
+import { unauthorized } from 'next/navigation'
+import db from '@/app/lib/db'
+
+export async function updateProfile(data) {
+ const session = await verifySession()
+
+ // If the user is not authenticated, return a 401
+ if (!session) {
+ unauthorized()
+ }
+
+ // Proceed with mutation
+ // ...
+}
+```
+
+### Fetching data with Route Handlers
+
+You can use `unauthorized` in Route Handlers to ensure only authenticated users can access the endpoint.
+
+```tsx filename="app/api/profile/route.ts" switcher
+import { NextRequest, NextResponse } from 'next/server'
+import { verifySession } from '@/app/lib/dal'
+import { unauthorized } from 'next/navigation'
+
+export async function GET(req: NextRequest): Promise {
+ // Verify the user's session
+ const session = await verifySession()
+
+ // If no session exists, return a 401 and render unauthorized.tsx
+ if (!session) {
+ unauthorized()
+ }
+
+ // Fetch data
+ // ...
+}
+```
+
+```jsx filename="app/api/profile/route.js" switcher
+import { verifySession } from '@/app/lib/dal'
+import { unauthorized } from 'next/navigation'
+
+export async function GET() {
+ const session = await verifySession()
+
+ // If the user is not authenticated, return a 401 and render unauthorized.tsx
+ if (!session) {
+ unauthorized()
+ }
+
+ // Fetch data
+ // ...
+}
+```
+
+## Version History
+
+| Version | Changes |
+| --------- | -------------------------- |
+| `v15.1.0` | `unauthorized` introduced. |
diff --git a/docs/01-app/03-api-reference/05-config/01-next-config-js/authInterrupts.mdx b/docs/01-app/03-api-reference/05-config/01-next-config-js/authInterrupts.mdx
new file mode 100644
index 0000000000000..6509d0ce55017
--- /dev/null
+++ b/docs/01-app/03-api-reference/05-config/01-next-config-js/authInterrupts.mdx
@@ -0,0 +1,33 @@
+---
+title: authInterrupts
+description: Learn how to enable the experimental `authInterrupts` configuration option to use `forbidden` and `unauthorized`.
+version: canary
+related:
+ links:
+ - app/api-reference/functions/forbidden
+ - app/api-reference/functions/unauthorized
+ - app/api-reference/file-conventions/forbidden
+ - app/api-reference/file-conventions/unauthorized
+---
+
+The `authInterrupts` configuration option allows you to use [`forbidden`](/docs/app/api-reference/functions/forbidden) and [`unauthorized`](/docs/app/api-reference/functions/unauthorized) APIs in your application. While these functions are experimental, you must enable the `authInterrupts` option in your `next.config.js` file to use them:
+
+```ts filename="next.config.ts" switcher
+import type { NextConfig } from 'next'
+
+const nextConfig: NextConfig = {
+ experimental: {
+ authInterrupts: true,
+ },
+}
+
+export default nextConfig
+```
+
+```js filename="next.config.js" switcher
+module.exports = {
+ experimental: {
+ authInterrupts: true,
+ },
+}
+```