Managing User Sessions Across A NextJS App And Chrome Extension

Managing User Sessions Across A NextJS App And Chrome Extension

While developing a Next.js web application alongside a browser extension, our team encountered a significant user login issue during testing. Although the initial development went smoothly, this problem negatively impacted the user experience. This post outlines the challenge we faced, our solution involving single sign-on (SSO), and the process we followed to implement it.

The Problem: Disconnected User Sessions

Users who registered and logged into the web application were required to sign in again when using the browser extension. This redundancy was not only inconvenient but also disrupted the seamless experience we aimed to provide. Recognizing the need for a unified authentication process, we set out to implement an SSO solution to synchronize user sessions across both platforms.

Our Solution: Implementing SSO with NextAuth

To address this issue, we utilized NextAuth to create a single sign-on system. The goal was to allow users to log in once on the web application and maintain that session across both the backend and the browser extension. This approach would eliminate the need for repeated authentication, enhancing the overall user experience.

The Implementation Process

Below is the step-by-step process we followed to implement the SSO solution.

1. Configuring NextAuth for Unified Authentication

We set up NextAuth to handle authentication for both the web app and the browser extension. The signIn callback was customized to manage user sessions effectively.

signIn: async ({ account, user }) => {
  try {
    const cookieStore = cookies();

    // Check for callbackUrl in production environment
    let callbackUrl = cookieStore.get('__Secure-next-auth.callback-url')?.value;

    // If no callbackUrl found, check using development cookie key name
    if (!callbackUrl) {
      callbackUrl = cookieStore.get('next-auth.callback-url')?.value;
    }

    // Extract and validate the user role
    const role = callbackUrl?.split('=').pop()?.toUpperCase() as RolesEnum;
    if (!role?.length || !allowedRoles.includes(role)) {
      return false;
    }

    // Validate the user with the backend
    const dbUser = await validateUser({
      access_token: account?.access_token,
      id_token: account?.id_token,
      as: role,
    });
    if (!dbUser.success) {
      return false;
    }

    // Bind additional properties to the user object
    user.accessToken = dbUser.data.accessToken;
    user.refreshToken = account?.refresh_token || '';
    user.id = dbUser.data.user.id;
    user.role = dbUser.data.user.role;
    user.image = dbUser.data.user.image;
    user.createdAt = dbUser.data.user.createdAt;
    user.name = dbUser.data.user.name;
    user.tokenExpires = account?.expires_at || 0;
    user.googleAccessToken = account?.access_token || '';

    return true;
  } catch (err) {
    console.log('Error in signIn callback', { err });
    return false;
  }
},

In this configuration:

  • Session Management: NextAuth handles the session with Google OAuth, while our backend maintains a session for user authentication.
  • Role Verification: The user's role is extracted from the callback URL and validated against allowed roles.
  • User Validation: The user is validated with the backend using tokens obtained from the authentication provider.
  • Session Persistence: User details and tokens are stored to maintain the session across the web app and extension.

2. Synchronizing Sessions with the Chrome Extension

We implemented a content script in the Chrome extension that interacts with the web application's session storage to synchronize authentication data.

// Check every second to see if the user is logged in
const interval = setInterval(() => {
  chrome.storage.local.set({
    session: JSON.parse(localStorage.getItem('session')),
  });
  chrome.storage.local.get(['session'], (result) => {
    if (result.session !== null) {
      clearInterval(interval);
    }
  });
}, 1000);

In this script:

  • Session Monitoring: The script periodically checks if the user is logged in by accessing the web app's localStorage.
  • Data Sharing: Upon detecting an active session, it stores the session data in the Chrome extension's chrome.storage.local.
  • Content Script: This approach leverages the content script's ability to access both the extension's and the web page's storage, enabling seamless data sharing.

3. Maintaining Session Consistency

By sharing the session data between the web app and the extension, we ensured that the user's authentication state remained consistent. This method eliminated the need for the user to log in separately on the extension, providing a unified and smooth user experience.


Implementing single sign-on using NextAuth allowed us to synchronize user authentication between our Next.js web application and the browser extension effectively. This solution streamlined the login process, reducing friction and enhancing user satisfaction. A seamless authentication experience is crucial for user retention, and our approach demonstrates how SSO can be successfully integrated into a serverless Next.js environment with a browser extension.

While developing a Next.js web application alongside a browser extension, our team encountered a significant user login issue during testing. Although the initial development went smoothly, this problem negatively impacted the user experience. This post outlines the challenge we faced, our solution involving single sign-on (SSO), and the process we followed to implement it.

The Problem: Disconnected User Sessions

Users who registered and logged into the web application were required to sign in again when using the browser extension. This redundancy was not only inconvenient but also disrupted the seamless experience we aimed to provide. Recognizing the need for a unified authentication process, we set out to implement an SSO solution to synchronize user sessions across both platforms.

Our Solution: Implementing SSO with NextAuth

To address this issue, we utilized NextAuth to create a single sign-on system. The goal was to allow users to log in once on the web application and maintain that session across both the backend and the browser extension. This approach would eliminate the need for repeated authentication, enhancing the overall user experience.

The Implementation Process

Below is the step-by-step process we followed to implement the SSO solution.

1. Configuring NextAuth for Unified Authentication

We set up NextAuth to handle authentication for both the web app and the browser extension. The signIn callback was customized to manage user sessions effectively.

signIn: async ({ account, user }) => {
  try {
    const cookieStore = cookies();

    // Check for callbackUrl in production environment
    let callbackUrl = cookieStore.get('__Secure-next-auth.callback-url')?.value;

    // If no callbackUrl found, check using development cookie key name
    if (!callbackUrl) {
      callbackUrl = cookieStore.get('next-auth.callback-url')?.value;
    }

    // Extract and validate the user role
    const role = callbackUrl?.split('=').pop()?.toUpperCase() as RolesEnum;
    if (!role?.length || !allowedRoles.includes(role)) {
      return false;
    }

    // Validate the user with the backend
    const dbUser = await validateUser({
      access_token: account?.access_token,
      id_token: account?.id_token,
      as: role,
    });
    if (!dbUser.success) {
      return false;
    }

    // Bind additional properties to the user object
    user.accessToken = dbUser.data.accessToken;
    user.refreshToken = account?.refresh_token || '';
    user.id = dbUser.data.user.id;
    user.role = dbUser.data.user.role;
    user.image = dbUser.data.user.image;
    user.createdAt = dbUser.data.user.createdAt;
    user.name = dbUser.data.user.name;
    user.tokenExpires = account?.expires_at || 0;
    user.googleAccessToken = account?.access_token || '';

    return true;
  } catch (err) {
    console.log('Error in signIn callback', { err });
    return false;
  }
},

In this configuration:

  • Session Management: NextAuth handles the session with Google OAuth, while our backend maintains a session for user authentication.
  • Role Verification: The user's role is extracted from the callback URL and validated against allowed roles.
  • User Validation: The user is validated with the backend using tokens obtained from the authentication provider.
  • Session Persistence: User details and tokens are stored to maintain the session across the web app and extension.

2. Synchronizing Sessions with the Chrome Extension

We implemented a content script in the Chrome extension that interacts with the web application's session storage to synchronize authentication data.

// Check every second to see if the user is logged in
const interval = setInterval(() => {
  chrome.storage.local.set({
    session: JSON.parse(localStorage.getItem('session')),
  });
  chrome.storage.local.get(['session'], (result) => {
    if (result.session !== null) {
      clearInterval(interval);
    }
  });
}, 1000);

In this script:

  • Session Monitoring: The script periodically checks if the user is logged in by accessing the web app's localStorage.
  • Data Sharing: Upon detecting an active session, it stores the session data in the Chrome extension's chrome.storage.local.
  • Content Script: This approach leverages the content script's ability to access both the extension's and the web page's storage, enabling seamless data sharing.

3. Maintaining Session Consistency

By sharing the session data between the web app and the extension, we ensured that the user's authentication state remained consistent. This method eliminated the need for the user to log in separately on the extension, providing a unified and smooth user experience.


Implementing single sign-on using NextAuth allowed us to synchronize user authentication between our Next.js web application and the browser extension effectively. This solution streamlined the login process, reducing friction and enhancing user satisfaction. A seamless authentication experience is crucial for user retention, and our approach demonstrates how SSO can be successfully integrated into a serverless Next.js environment with a browser extension.

CONSULT WITH EXPERTS REGARDING YOUR PROJECT

We have a team who’s ready to make your dreams into a reality. Let us know what you have in mind.

Read More

INTERESTED IN WORKING WITH US?

Let’s Talk And Get Started