Secure your NextJS Apps with Azure AD and NextAuth (Part 4)

Using NextAuth in Your Application

Dewaun Ayers
5 min readMar 5, 2023

Disclaimer: This is part 4 of a 7 part tutorial. Click the below link to go back to Part 1 to learn more about the intent of this tutorial.

Part 1 — Introduction and “What is an Identity Provider?”

Or go back to Part 3 — Project Setup: Next.js + Serverless Stack (SST) + AWS

What is NextAuth?

According to the NextAuth.js team:

NextAuth.js is a complete open-source authentication solution for Next,js Appplications … designed from the ground up to support Next.js and Serverless

With NextAuth.js you can set up authentication in your app with very little setup. Simply choose a provider, plugin in your IdP details, and set up your NextAuth config in your Next.js application. NextAuth provides tooling for signing in, signing out, maintaining sessions on the server-side or in a database, and decoding or modifying tokens.

Note: At the time of publishing this tutorial, NextAuth announced they are becoming Auth.js. Don’t worry, the APIs are the same, and the documentation is even better. Auth.js is an expansion on NextAuth that aims to bring auth to more than just Next.js applications. You can check out the Auth.js site here.

Adding NextAuth to Your Project

Run the following code to install NextAuth

$ cd frontend
$ npm i next-auth

When that’s done create some environment variables to use with NextAuth. Create a .env.local file in the frontend directory

Now lets add a NEXTAUTH_SECRET value.

NEXTAUTH_SECRET=SomeStringThatIs32CharactersLong

This value can be anything as long as it’s 32 characters in length. You can use the following command to generate a randomized value that works

$ openssl rand -base64 32

Remember when we set up Azure Active Directory? Let’s go back to Azure AD and grab the values for our environment variables and add them to a .env.local file as well. These values can be found in the Overview >> Essentials tab for the app you registered. The Client Secret is the same value you were told to (and hopefully did!) store in a secure location during the app registration instructions.

AZURE_AD_CLIENT_ID=YOUR-AD-CLIENT-ID # Application (client) ID
AZURE_AD_CLIENT_SECRET=YOUR-AD-CLIENT-SECRET # Client Credentials
AZURE_AD_TENANT_ID=YOUR-AD-TENANT-ID # Directory (tenant) ID

Now onto the code!

Create a [...nextauth].ts file in pages/api/auth and add the following code

// pages/api/auth/[...nextauth].ts
import NextAuth, { AuthOptions } from "next-auth";
import AzureADProvider from "next-auth/providers/azure-ad";

export const authOptions: AuthOptions = {
// Configure one or more authentication providers
providers: [
AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID!,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET!,
tenantId: process.env.AZURE_AD_TENANT_ID!,
authorization: { params: { scope: "openid profile user.Read email" } },
}),
],
callbacks: {
async jwt({ token, account }) {
// IMPORTANT: Persist the access_token to the token right after sign in
if (account) {
token.idToken = account.id_token;
}
return token;
},
},
};
export default NextAuth(authOptions);

This will set up an Azure AD provider via NextAuth and handle redirects to sign in and sign out functionality. The callbacks > jwt entry makes sure that we add the idToken (that we enabled in the Azure AD App Registration) to the token. We will need this later in the tutorial.

Modify the layout.tsx file to include the NextAuth Session provider component. This will wrap all of our client components in the Session provider and give them access to next-auth hooks like useSession (as seen above)

// app/layout.tsx
"use client";
import { SessionProvider } from "next-auth/react";
import "./globals.css";

export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
{/*
<head /> will contain the components returned by the nearest parent
head.tsx. Find out more at https://beta.nextjs.org/docs/api-reference/file-conventions/head
*/}
<head />
<body>
<SessionProvider>{children}</SessionProvider>
</body>
</html>
);
}

Next we want to add a simple login button to the default NextJS UI.

In the app directory create a LoginButton.tsx React component

// app/LoginButton.tsx
"use client";
import { useSession, signIn, signOut } from "next-auth/react";

export const LoginButton = () => {
const { data: session } = useSession();
if (session) {
return (
<>
Signed in as {session?.user?.email} <br />
<button onClick={() => signOut()}>Sign out</button>
</>
);
}
return (
<>
Not signed in <br />
<button
onClick={() => {
console.log("logging in?");
signIn();
}}
>
Sign in
</button>
</>
);
};

In page.tsx you can import the LoginButton and place it anywhere you like. For reference, I placed mine right after the NextJS 13 logo

In your terminal you can start the Next.js App by running

$ cd frontend
$ npm run dev

Navigate to http://localhost:3000 in your browser and click the Sign in button. This should redirect you to a new page with some UI to initiate the login process for Azure AD

Click the Sign in with Azure Active Directory button and complete your log in.

If all has gone well you should be redirected back to the home page with an update in the UI signifying you are logged in.

Now that we’ve handled securing the client-side of our application, let’s move on to locking down our API routes on the server-side in Part 5

What’s next?

Part 5 — Securing your API Routes with NextAuth
Part 6 — Deploying with Serverless Stack
Part 7 — Third-Party Authentication and Authorization with AWS AppSync

My goal is to provide content that leaves readers with a bit more knowledge than they started with.

If this tutorial helped you in anyway please leave a clap or two! If you have any questions or I got something wrong, leave a comment and let me know how I can improve!

--

--

Dewaun Ayers
Dewaun Ayers

Written by Dewaun Ayers

I'm a Frontend Dev living in Melbourne, Australia and studying Computer Science. I love anything to do with web tech and am constantly trying to learn more!

Responses (5)