Secure your NextJS Apps with Azure AD and NextAuth (Part 4)
Using NextAuth in Your Application
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
Tools used in this tutorial
Core Concepts
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!