Integration Guide: NextAuth Meets Azure AD B2C for Sitecore Headless

Master Azure AD B2C and NextAuth setup for Secure Sitecore Headless Login

November 25, 2024

By Karan Patel

Configure Azure AD B2C Provider for NextAuth

Authentication is a critical aspect of any modern web application, and NextAuth makes it incredibly flexible. While our previous series, Unlock Seamless Authentication, focused on credentials-based authentication, designing a form and user flows, this guide will focus on adding Azure Active Directory B2C as a provider. Whether you're expanding your project or exploring advanced identity integrations, this step-by-step guide simplifies the process by breaking down complex configurations into manageable steps. If you haven’t checked out our series, we highly recommend so before moving further as we won’t be going over the installation or any of the user flow part in this one. We’ll only focus on the following:

  • ENV variables
  • Add AzureB2C Provider
  • Setup Login and Logout functionality

Note: It is assumed that you’ve created a Azure AD B2C Tenant, have an app registration and is configured with a user flow. If you’ve not, then checkout the tutorials from Microsoft on Create an Azure Active Directory B2C tenant.

Why Azure AD B2C?

Azure AD B2C offers a robust, enterprise-grade identity solution that's ideal for businesses with diverse authentication needs. Unlike standard NextAuth providers like Google or GitHub, which focus mainly on social logins, Azure AD B2C supports a wide range of authentication methods—email, phone, social accounts, and even corporate directories. It also provides greater customizability, allowing businesses to tailor the login experience to their brand and security standards. If you're looking for a scalable, secure authentication system that integrates well with Microsoft services and supports large user bases, Azure AD B2C is a powerful choice over traditional social logins. Here’s how it compares:

Enterprise-Grade Security and Scalability

Unlike social login providers, Azure AD B2C is designed to meet enterprise security standards with added benefit of compliance, such as GDPR and HIPPA. It's designed to scale with your organization, making it a great choice for businesses that need a robust, secure authentication system to handle millions of users.

Customizability

Azure AD B2C allows for complete customization of the authentication flow, from branded login screens to custom workflows. This flexibility goes beyond the more limited customization options of social providers.

User Data Control

With Azure AD B2C, you retain greater control over user data, and it integrates seamlessly with Microsoft services, making it a strong choice for businesses already using Azure or Office 365.

Cross-Platform Integration

Azure AD B2C supports multiple identity protocols, allowing you to connect with various applications, internal systems, and external services with ease—something most social logins don’t offer.

Essential Env Variables

Now that we know the advantages of Azure AD B2C, we’ll move on integration part. First up we need are env variables. In order to add the provider, we’ll have to add the following into .env file.

Name Sample Value Description
TENANT_NAME getfishtank-azureb2c-demo The name when you create the Azure tenant. It the prefix of the domain getfishtank-azureb2c-demo.onmicrosoft.com.
PRIMARY_USER_FLOW B2C_1A_GETFISHTANK_SIGNUPORSIGNIN User flow determines how users interact with the registered application.
LOGOUT_REDIRECT_URI http://localhost:3000 After signing out, Azure AD B2C would redirect to this URL. For upstream environments, configure it to be the website domain.
CLIENT_SECRET xxxxx Before the website can interact with Azure AD B2C, it needs to be registered within the tenant. Once you register you can create the secret which will be used here.
CLIENT_ID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx The application (client) id is the value when you register the website.

All of these variables will be used when we configure the provider except LOGOUT_REDIRECT_URI. As mentioned earlier, we are assuming that the Azure AD B2C tenant, app registration and user flows are already setup.

Adding Azure AD B2C Provider

Once we’ve our important env variables, it is now time to put them to use. We’ll first create the types in case if the project is using TypeScript. Next, we’ll add the actual provider and then at last, we’ll define the callback function.

// src/types/next-auth.d.ts

import NextAuth, { DefaultSession } from 'next-auth';

declare module 'next-auth' {

  interface Session {
    accessToken?: string;
    user: {
      name: string;
      email: string;
      sub: string | undefined;
    };
    error?: string;
  }

  interface Profile {
    email?: string;
    name?: string;
  }
}

declare module 'next-auth/jwt' {
  interface JWT {
    /** OpenID ID Token */
    accessToken?: string;
    accessTokenExpires: number;
    error?: string;
  }
}

The types only include the accessToken and its expiry. If you have a refreshToken and its expiry, then modify it accordingly. Moving on, let’s define the provider. Use the following code to do so.

// src/pages/api/[...nextauth].ts

import NextAuth from 'next-auth';
import AzureADB2CProvider from 'next-auth/providers/azure-ad-b2c';
import type { NextAuthOptions } from 'next-auth';

export const authOptions: NextAuthOptions = {
  providers: [
    AzureADB2CProvider({
      tenantId: process.env.TENANT_NAME,
      clientId: process.env.CLIENT_ID || '',
      clientSecret: process.env.CLIENT_SECRET || '',
      primaryUserFlow: process.env.PRIMARY_USER_FLOW,
      authorization: {
        params: {
          scope: 'offline_access openid',
        },
      },
      checks: ['pkce'],
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
  callbacks: {
    //CallBack code goes here...
  },
  pages: {
    signIn: '/login', // Custom sign in page if you have one
  },
};

const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

The callback function will handle what will happen after the user has successfully logged in. This is where we’ll write the logic of what needs to be sent to user and also handle the expiry.

callbacks: {
  async signIn({ account, profile }) {
    if (account && profile) {
      return true;
    }
    return true;
  },
  async jwt({ token, account, user, profile }) 
    if (account) {
      token.accessToken = account.id_token;
      token.accessTokenExpires = Date.now() + account.id_token_expires_in * 1000;
      //Add refreshToken and its expiry here if you have them
    }

    if (profile) {
      token.email = profile?.email;
    }

    // Skip the conditional logic if don't have a refreshToken and simply return the token.
    // return token if expiry is more than 5 minutes away.
    if (Date.now() < token.accessTokenExpires - 300 * 1000) {
      return token;
    }

    //Create a refreshAccessToken function to handle token refresh and return it.
    //const refreshedToken = await refreshAccessToken(token);
    //return refreshedToken;
  },
  async session({ session, token }) {
    session.accessToken = token.accessToken;
    session.user.sub = token.sub;
    session.error = token.error;

    return session;
  },
},

Setting Up Login and Logout Functionality

The Azure AD B2C provider is configured, so the next step is to manage the user login and logout processes. This section will handle those flows ensuring users can securely authenticate and sign out.

Login

When a user attempts to log in, they will be redirected to the Azure AD B2C login page, where they can authenticate using their chosen method, whether it’s through a social account, email, or another identity provider. After successful authentication, Azure AD B2C will redirect them back to your application, and NextAuth will handle the session creation, storing the authentication information securely. To do so, add the following code to the component that has the login button.

// src/components/authentication/Login.tsx

import React from 'react';
...

const Login = (): JSX.Element => {
  ...
  return (
    <div className="">
      <button onClick={() => signIn('azure-ad-b2c', { callbackUrl: '/', redirect: false })}>
        Login
      </button>
    </div>
  );
};

export default Login;

//Set redirect to false if you want to disable the back button if you have a /login page

Logout

For logging out, NextAuth provides an easy-to-use signOut() function. When triggered, this will clear the session data on both the client and server side, ensuring the user is fully logged out of the application. In the case of Azure AD B2C, you can also configure it to sign the user out of the identity provider, which will ensure they are not automatically logged back in if they visit the login page again.

// Probably a menu or navigation component

<button onClick={() => {
    signOut({
      redirect: false, //set it false as the logout from B2C will handle the redirect
    })
    logoutAzureADB2C();
  }}
>
  Logout
</button>

//Add this function to logout from B2C
async function logoutAzureADB2C() {
  router.push("https://${process.env.TENANT_NAME}.b2clogin.com/${process.env.TENANT_NAME}.onmicrosoft.com/${process.env.PRIMARY_USER_FLOW}/oauth2/v2.0/logout?post_logout_redirect_uri=${process.env.LOGOUT_REDIRECT_URI}");
}

This seamless login/logout process helps maintain a smooth and secure user experience while working with Azure AD B2C.

Troubleshooting and Final Thoughts

You might run into an error called OAUTH_PARSE_PROFILE_ERROR . This basically occurs if the profile object that is sent back by Azure AD B2C doesn’t contain the emails key. Remember, we have email in our type file as that is what our Azure AD B2C sent us. So, to resolve this issue, add the following in the provider.

AzureADB2CProvider({
  tenantId: process.env.TENANT_NAME,
    ...
  checks: ['pkce'],
  // To resolve OAUTH_PARSE_PROFILE_ERROR
  profile: (oauthProfile) => ({
    id: oauthProfile.sub,
    name: oauthProfile.name,
  }),
})

It is also important to configure the redirect URI within the app registration for your Azure AD B2C tenant. Add the following when you register an app to avoid callback errors.

https://<YOUR_DOMAIN>/api/auth/callback/azure-ad-b2c

That’s it folks! This guide covered the essential steps; setting up environment variables, configuring the Azure B2C provider, and managing login and logout processes enabling you to enhance your authentication strategy. With these steps, you’ve successfully integrated Azure AD B2C with NextAuth for your Sitecore Headless solution providing a powerful and scalable authentication solution.

Karan Developer

Karan Patel

Sitecore Developer

Karan is a Sitecore Certified Developer with over 2 years of experience building and implementing Sitecore solutions using ASP .NET MVC, React, Azure and AWS. He's an avid fan of Counter-Strike and can usually be found playing it if he is not developing. In his spare time, he likes to play guitar and cook Indian food.