Type something to search...
Next.js unauthorized.js

Next.js unauthorized.js

unauthorized.js completes a trio of authorization-adjacent special files alongside forbidden.js and the long-standing not-found.js — and of the three, it's the one that maps most directly onto a scenario every app with a login flow eventually has to handle: someone visiting a page that requires being signed in, while they aren't. Where forbidden.js says "you're logged in, but this still isn't for you," unauthorized.js says the more fundamental "you're not logged in at all, and this page requires it" — a genuinely distinct condition, with its own correct HTTP status code and its own dedicated file convention.

Basic Usage

import Login from "@/app/components/Login";

export default function Unauthorized() {
  return (
    <main>
      <h1>401 - Unauthorized</h1>
      <p>Please log in to access this page.</p>
      <Login />
    </main>
  );
}

This renders whenever your code calls the paired unauthorized() function (from next/navigation) inside a route segment, and Next.js returns a 401 status code alongside it — the correct HTTP status for "authentication is required and has not been provided," distinct from both 404 (nothing here) and 403 (something's here, but you can't have it regardless of who you are).

401 vs. 403 vs. 404 — Getting the Semantics Right

It's worth being precise about this distinction, since conflating any two of these status codes genuinely confuses both users and any tooling reading your responses:

  • 401 (Unauthorized) — the visitor isn't authenticated at all. The fix is to log in; access might well be granted immediately afterward.
  • 403 (Forbidden) — the visitor is authenticated, but their identity doesn't have permission for this specific resource. Logging in again wouldn't help — a different account, or a different permission level, would.
  • 404 (Not Found) — you're deliberately not confirming the resource exists at all, to anyone who isn't authorized to know that.

unauthorized.js is specifically for the first case. Reaching for forbidden() or notFound() when what you actually mean is "please log in" sends a status code (and a message) that doesn't match the real situation, and can send genuinely confused users down the wrong troubleshooting path — retrying, refreshing, assuming it's a bug — when the actual fix is simply signing in.

Props

Like forbidden.js, unauthorized.js components accept no props at all — a pure, static fallback component. Any context about why access was denied has to be communicated through some other channel your own code controls, not through anything this file receives automatically.

Example: Gating a Page and Showing a Login UI

The canonical pattern pairs a session check inside a page with the unauthorized() function, and a matching unauthorized.js that renders the actual login experience:

import { verifySession } from "@/app/lib/dal";
import { unauthorized } from "next/navigation";

export default async function DashboardPage() {
  const session = await verifySession();

  if (!session) {
    unauthorized();
  }

  return <div>Dashboard</div>;
}
import Login from "@/app/components/Login";

export default function UnauthorizedPage() {
  return (
    <main>
      <h1>401 - Unauthorized</h1>
      <p>Please log in to access this page.</p>
      <Login />
    </main>
  );
}

Calling verifySession() inside the Data Access Layer (rather than trusting a client-passed flag) and checking its result directly in the page is the pattern worth internalizing here, independent of this specific file — unauthorized() is only as trustworthy as the session check that decides to call it. The file itself is just the UI half of the pair; the actual security boundary lives in verifySession and wherever else your app validates that a session is genuinely real.

Experimental Status — Read Before Shipping This

Exactly like forbidden.js, this convention is explicitly marked experimental and not recommended for production as of this writing. That has concrete implications for how you should plan around it:

  • The function signature, the file's behavior, or its continued existence could change in a future release without the deprecation runway a stable API would get.
  • If you need reliable 401 handling in production today, building it yourself — checking session state and rendering a 401-styled response directly, without relying on this specific convention — is the more conservative choice until it stabilizes.
  • The Next.js team explicitly solicits feedback on this feature via GitHub issues, which is the right channel if you do experiment with it and hit rough edges worth reporting.

Version History

VersionChanges
v15.1.0unauthorized.js introduced

Key Takeaways

AspectDetail
Triggered byThe unauthorized() function, called from next/navigation
Status code401
PropsNone — a static component
vs. forbidden.jsUse 401 when the visitor isn't authenticated at all; use 403 when they are, but still lack permission
Typical pairingA session check (via your Data Access Layer) that calls unauthorized() on failure
StatusExperimental — not recommended for production as of this writing

The value of having a dedicated unauthorized.js rather than reusing notFound() or a generic error page for every access-denial scenario is precision: users (and any monitoring reading your response codes) get an honest, specific signal about exactly what went wrong and what would actually fix it. Just build with the awareness that this particular convention is still evolving, and plan your production authentication flow with that in mind until it stabilizes.

Tags :
Share :

Related Posts

Can Next.js Be Used with GraphQL?

Can Next.js Be Used with GraphQL?

Next.js and GraphQL are two powerful technologies that have gained significant traction in the web development community. Next.js, a React-based fram

Dive Deeper
How does Next.js differ from Create React App?

How does Next.js differ from Create React App?

In the world of modern web development, React.js has emerged as a dominant force due to its flexibility, performance, and extensive ecosystem. Two po

Dive Deeper
How does Next.js handle image optimization?

How does Next.js handle image optimization?

In modern web development, image optimization plays a critical role in enhancing user experience and improving site performance. Large, unoptimized i

Dive Deeper