App Router - Adding Authentication - Next - Js
App Router - Adding Authentication - Next - Js
js
Chapter 15
Sign in
Adding Authentication
15
Adding Authentication
In the previous chapter, you finished building the invoices routes by adding form validation
and improving accessibility. In this chapter, you'll be adding authentication to your
dashboard.
In this chapter...
Here are the topics we’ll cover
What is authentication.
How to use React's useActionState to handle pending states and form errors.
What is authentication?
Authentication is a key part of many web applications today. It's how a system checks if the
user is who they say they are.
A secure website often uses multiple ways to check a user's identity. For instance, after
entering your username and password, the site may send a verification code to your device
or use an external app like Google Authenticator. This 2-factor authentication (2FA) helps
increase security. Even if someone learns your password, they can't access your account
without your unique token.
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 1/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
Authentication is about making sure the user is who they say they are. You're proving
your identity with something you have like a username and password.
Authorization is the next step. Once a user's identity is confirmed, authorization decides
what parts of the application they are allowed to use.
So, authentication checks who you are, and authorization determines what you can do or
access in the application.
Which of the following best describes the difference between authentication and
authorization?
C
Authentication verifies your identity. Authorization determines what you can
access.
Correct
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 2/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
Chapter 15
Sign in
Creating the login route
Adding Authentication
Start by creating a new route in your application called /login and paste the following
code:
/app/login/page.tsx
You'll notice the page imports <LoginForm /> , which you'll update later in the chapter. This
component is wrapped with React <Suspense> because it will access information from the
incoming request (URL search params).
NextAuth.js
We will be using NextAuth.js to add authentication to your application. NextAuth.js
abstracts away much of the complexity involved in managing sessions, sign-in and sign-out,
and other aspects of authentication. While you can manually implement these features, the
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 3/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
Setting up NextAuth.js
Install NextAuth.js by running the following command in your terminal:
Terminal
pnpm i next-auth@beta
Here, you're installing the beta version of NextAuth.js, which is compatible with Next.js 14+.
Next, generate a secret key for your application. This key is used to encrypt cookies, ensuring
the security of user sessions. You can do this by running the following command in your
terminal:
Terminal
# macOS
openssl rand -base64 32
# Windows can use https://generate-secret.vercel.app/32
Then, in your .env file, add your generated key to the AUTH_SECRET variable:
.env
AUTH_SECRET=your-secret-key
For auth to work in production, you'll need to update your environment variables in your
Vercel project too. Check out this guide on how to add environment variables on Vercel.
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 4/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
Create an auth.config.ts file at the root of our project that exports an authConfig
Chapter 15
object. This object will contain the configuration options for NextAuth.js. For now,Sign
it will
in only
Adding Authentication
contain the pages option:
/auth.config.ts
You can use the pages option to specify the route for custom sign-in, sign-out, and error
pages. This is not required, but by adding signIn: '/login' into our pages option, the
user will be redirected to our custom login page, rather than the NextAuth.js default page.
/auth.config.ts
The authorized callback is used to verify if the request is authorized to access a page with
Next.js Middleware. It is called before a request is completed, and it receives an object with
the auth and request properties. The auth property contains the user's session, and the
request property contains the incoming request.
The providers option is an array where you list different login options. For now, it's an
empty array to satisfy NextAuth config. You'll learn more about it in the Adding the
Credentials provider section.
Next, you will need to import the authConfig object into a Middleware file. In the root of
your project, create a file called middleware.ts and paste the following code:
/middleware.ts
Here you're initializing NextAuth.js with the authConfig object and exporting the auth
property. You're also using the matcher option from Middleware to specify that it should run
on specific paths.
The advantage of employing Middleware for this task is that the protected routes will not
even start rendering until the Middleware verifies the authentication, enhancing both the
security and performance of your application.
Password hashing
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 6/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
It's good practice to hash passwords before storing them in a database. Hashing converts a
Chapter 15
password into a fixed-length string of characters, which appears random, providing
Signainlayer of
Adding Authentication
security even if the user's data is exposed.
When seeding your database, you used a package called bcrypt to hash the user's
password before storing it in the database. You will use it again later in this chapter to
compare that the password entered by the user matches the one in the database. However,
you will need to create a separate file for the bcrypt package. This is because bcrypt
relies on Node.js APIs not available in Next.js Middleware.
Create a new file called auth.ts that spreads your authConfig object:
/auth.ts
The Credentials provider allows users to log in with a username and a password.
/auth.ts
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 7/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
Good to know:
Chapter 15
Sign in
There Adding
are otherAuthentication
alternative providers such as OAuth or email . See the NextAuth.js docs for a
full list of options.
/auth.ts
After validating the credentials, create a new getUser function that queries the user from
the database.
/auth.ts
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 8/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
const sql = postgres(process.env.POSTGRES_URL!, { ssl: 'require' });
Chapter 15
Sign in
Adding
async Authentication
function getUser(email: string): Promise<User | undefined> {
try {
const user = await sql<User[]>`SELECT * FROM users WHERE email=${email}`;
return user[0];
} catch (error) {
console.error('Failed to fetch user:', error);
throw new Error('Failed to fetch user.');
}
}
if (parsedCredentials.success) {
const { email, password } = parsedCredentials.data;
const user = await getUser(email);
if (!user) return null;
}
return null;
},
}),
],
});
/auth.ts
// ...
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 9/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
export const { auth, signIn, signOut } = NextAuth({
Chapter 15
...authConfig,
Sign in
Adding Authentication
providers: [
Credentials({
async authorize(credentials) {
// ...
if (parsedCredentials.success) {
const { email, password } = parsedCredentials.data;
const user = await getUser(email);
if (!user) return null;
const passwordsMatch = await bcrypt.compare(password, user.password);
console.log('Invalid credentials');
return null;
},
}),
],
});
Finally, if the passwords match you want to return the user, otherwise, return null to
prevent the user from logging in.
/app/lib/actions.ts
'use server';
// ...
If there's a 'CredentialsSignin' error, you want to show an appropriate error message. You
can learn about NextAuth.js errors in the documentation
Finally, in your login-form.tsx component, you can use React's useActionState to call
the server action, handle form errors, and display the form's pending state:
app/ui/login-form.tsx
'use client';
return (
<form action={formAction} className="space-y-3">
<div className="flex-1 rounded-lg bg-gray-50 px-6 pb-4 pt-8">
<h1 className={`${lusitana.className} mb-3 text-2xl`}>
Please log in to continue.
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 11/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
</h1>
Chapter
<div15 className="w-full">
Sign in
Adding <div>
Authentication
<label
className="mb-3 mt-5 block text-xs font-medium text-gray-900"
htmlFor="email"
>
Email
</label>
<div className="relative">
<input
className="peer block w-full rounded-md border border-gray-200 py-[9
id="email"
type="email"
name="email"
placeholder="Enter your email address"
required
/>
<AtSymbolIcon className="pointer-events-none absolute left-3 top-1/2 h
</div>
</div>
<div className="mt-4">
<label
className="mb-3 mt-5 block text-xs font-medium text-gray-900"
htmlFor="password"
>
Password
</label>
<div className="relative">
<input
className="peer block w-full rounded-md border border-gray-200 py-[9
id="password"
type="password"
name="password"
placeholder="Enter password"
required
minLength={6}
/>
<KeyIcon className="pointer-events-none absolute left-3 top-1/2 h-[18px
</div>
</div>
</div>
<input type="hidden" name="redirectTo" value={callbackUrl} />
<Button className="mt-4 w-full" aria-disabled={isPending}>
Log in <ArrowRightIcon className="ml-auto h-5 w-5 text-gray-50" />
</Button>
<div
className="flex h-8 items-end space-x-1"
aria-live="polite"
aria-atomic="true"
>
{errorMessage && (
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 12/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
<>
Chapter 15 <ExclamationCircleIcon className="h-5 w-5 text-red-500" />
Sign in
Adding Authentication
<p className="text-sm text-red-500">{errorMessage}</p>
</>
)}
</div>
</div>
</form>
);
}
/ui/dashboard/sidenav.tsx
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 13/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
</div>
);Chapter 15
Sign in
} Adding Authentication
Try it out
Now, try it out. You should be able to log in and out of your application using the following
credentials:
Email: [email protected]
Password: 123456
15
You've Completed Chapter 15
You added authentication to your application and protected your dashboard routes.
Next Up
16: Adding Metadata
Finish your application by learning how to add metadata in preparation for sharing.
Start Chapter 16
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 14/15
2025/9/5 14:45 App Router: Adding Authentication | Next.js
Chapter 15
Sign in
Adding Authentication
Resources More About Vercel Legal
[email protected] Subscribe
https://nextjs.org/learn/dashboard-app/adding-authentication#authentication-vs-authorization 15/15