Next.js + NextAuth.js — Session Management and Role-Based Access

Next.js + NextAuth.js — Session Management and Role-Based Access

In the previous post, we integrated Keycloak with NextAuth.js. Now we’ll focus on **managing sessions, applying roles, and protecting pages and API routes** in a Next.js frontend.


1️⃣ Accessing the session

NextAuth.js provides two main ways to access the session:

  • Client-side: using useSession() hook
  • Server-side: using getSession() in getServerSideProps or API routes

Example (client-side):



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

export default function Dashboard() {

  const { data: session } = useSession();

  if (!session) return <p>Please sign in</p>;

  return <div>Welcome {session.user.name}</div>;

}

Example (server-side):



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

export async function getServerSideProps(context) {

  const session = await getSession(context);

  if (!session) {

    return {

      redirect: {

        destination: "/api/auth/signin",

        permanent: false

      }

    };

  }

  return { props: { session } };

}


2️⃣ Role-based access

You can enforce roles by using **callbacks** in NextAuth.js to add roles to the session:



callbacks: {

  async jwt({ token, account, profile }) {

    if (account && profile) {

      token.role = profile.role || "USER"; // get role from Keycloak claim

    }

    return token;

  },

  async session({ session, token }) {

    session.user.role = token.role;

    return session;

  }

}

Then protect pages based on role:



if (session.user.role !== "ADMIN") {

  return <p>Access denied</p>;

}


3️⃣ Protecting API routes

NextAuth.js can protect **Next.js API routes** using getServerSession:



import { getServerSession } from "next-auth/next";

import { authOptions } from "./[...nextauth]";

export default async function handler(req, res) {

  const session = await getServerSession(req, res, authOptions);

  if (!session) {

    return res.status(401).json({ message: "Unauthorized" });

  }

  if (session.user.role !== "ADMIN") {

    return res.status(403).json({ message: "Forbidden" });

  }

  res.status(200).json({ data: "Protected content" });

}

> This ensures your API routes respect SSO authentication and roles.


4️⃣ Refreshing tokens

Access tokens expire. NextAuth.js supports refreshing tokens via **JWT callback**:



async jwt({ token, account }) {

  if (account) {

    token.accessToken = account.access_token;

    token.expires = Date.now() + account.expires_in * 1000;

  }

  if (Date.now() > token.expires) {

    // call your refresh token endpoint

    const refreshedTokens = await refreshAccessToken(token);

    token.accessToken = refreshedTokens.accessToken;

    token.expires = refreshedTokens.expires;

  }

  return token;

}

> Always handle token refresh for API calls to avoid 401 errors.


5️⃣ Debugging session and roles

  • Log the session object on client and server
  • Verify Keycloak claims are correctly mapped
  • Check for redirect loops on protected pages
  • Ensure JWT strategy is consistent for API calls

Next steps

The final post in this frontend SSO series will cover **debugging SSO in Next.js**, including token issues, redirect loops, and API errors. It will give you a **complete workflow to troubleshoot frontend SSO**.

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