Next.js + NextAuth.js — Manager Approval Flow with Popup Login

Next.js + NextAuth.js — Manager Approval Flow with Popup Login

In some workflows, you need a manager to approve actions without logging out the current user. This post shows how to implement a Manager Approval Flow using NextAuth.js and a separate popup login, ensuring valid manager roles and token handling.


1️⃣ Overview of the flow

The flow works like this:

  1. The user triggers an action requiring manager approval.
  2. A popup opens with a separate NextAuth.js client configured for manager login.
  3. The manager signs in.
  4. We get the access_token and validate that the manager has the required role.
  5. If valid, send a message to the opener and close the popup.
  6. If invalid or login fails, show an error in the popup and allow retry.
  7. Always log out the manager and clear cookies after each approval attempt.

2️⃣ Setting up a separate client for manager login

You need a separate Keycloak client ID for the manager flow, but the same provider:



providers: [

  KeycloakProvider({

    clientId: process.env.MANAGER_CLIENT_ID,

    clientSecret: process.env.MANAGER_CLIENT_SECRET,

    issuer: process.env.KEYCLOAK_ISSUER

  })

]

> This allows the manager login to be isolated from the main user session.


3️⃣ Popup login page

Open a popup window when manager approval is needed:



function openManagerPopup() {

  const popup = window.open(

    "/manager-login",

    "managerLogin",

    "width=500,height=600"

  );

  window.addEventListener("message", (event) => {

    if (event.data.type === "manager-approved") {

      console.log("Manager approved:", event.data);

      // Proceed with approval

    }

  });

}

The popup page points to a Next.js page with NextAuth.js sign-in for the manager.


4️⃣ Sign-in callback and role verification



callbacks: {

  async signIn({ user, account }) {

    if (account) {

      const accessToken = account.access_token;

      // Call backend API to verify manager role

      const res = await fetch("/api/verify-manager", {

        method: "POST",

        headers: { Authorization: `Bearer ${accessToken}` }

      });

      const data = await res.json();

      if (!data.isManager) {

        return "/manager-login?error=not_manager"; // redirect back to popup with error

      }

    }

    return true;

  }

}

> The backend verifies the token and ensures the manager has the required role.


5️⃣ Posting message to opener

Once verified, send a message from the popup to the main window:



if (window.opener) {

  window.opener.postMessage(

    { type: "manager-approved", user: session.user },

    window.location.origin

  );

  // Close popup

  window.close();

}


6️⃣ Logout and cleanup

For security, always log out the manager and clean up cookies, so each approval requires a fresh login:



import { signOut } from "next-auth/react";

await signOut({ redirect: false });

// Optional: clear cookies manually if needed

document.cookie = "next-auth.session-token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT";

> This ensures no stale tokens are left, and the next approval will require login again.


7️⃣ Backend token verification

Implement an API endpoint to validate manager token:



export default async function handler(req, res) {

  const token = req.headers.authorization?.split(" ")[1];

  if (!token) return res.status(401).json({ isManager: false });

  try {

    const decoded = await verifyToken(token); // your JWT verification logic

    if (decoded.roles?.includes("MANAGER")) {

      res.status(200).json({ isManager: true });

    } else {

      res.status(403).json({ isManager: false });

    }

  } catch (err) {

    res.status(401).json({ isManager: false });

  }

}


8️⃣ Error handling and retry

If the manager login fails or the role is invalid:

  • Redirect back to the popup login page with an error query string.
  • Show a user-friendly error message.
  • Allow the manager to sign in again.

Conclusion

This popup-based Manager Approval Flow ensures:

  • Manager login is isolated from main user session
  • Access token is fresh every login
  • Manager role is validated securely
  • Error handling and logout cleanup are done correctly

It’s ideal for workflows that require manager approval without affecting the main user session.

Part of the Next.js Frontend SSO Series

❤️ Support This Blog


If this post helped you, you can support my writing with a small donation. Thank you for reading.


Comments

Popular posts from this blog

fixed: embedded-redis: Unable to run on macOS Sonoma

Copying MDC Context Map in Web Clients: A Comprehensive Guide

Reset user password for your own Ghost blog