'Role based permissions for api access in middleware NextJS

Is there a way to do role based permissions in middleware? I'm asking this because I was hoping that there would be a way to call getSession in middleware. Otherwise I would need to implement a helper function hasPermissions(req), import it and call it in every single file and I'm trying to avoid that Thanks



Solution 1:[1]

if you do not want to use third party authenticatio server and you want to do on your own, you could write this with using cookeis and jwt.

1- when users logins set a jwt token. In next.js when user logins, make a request to api function and api function should handle the login process:

import jwt from "jsonwebtoken";

const handleLoginWithEmail = async (e) => {
  e.preventDefault();
  if (email) {
    try {
      //... add your logic, set state 
      // make a 
      const response = await fetch("/api/login", {
        method: "POST",
        headers: {
          // pass this if you are using passwdrdless or other service that needs token
          Authorization: `Bearer ${ifToken}`,
          "Content-Type": "application/json",
        },
      });
    } catch (error) {
      console.error("Something went wrong logging in", error);
    }
  }
};

your api function should create a jwt

export default async function login(req, res) {
  if (req.method === "POST") {
    try {
      // if there is
      const auth = req.headers.authorization;
      // add your logic
      const token = jwt.sign(
        {
          ...metadata,
          iat: Math.floor(Date.now() / 1000),
          exp: Math.floor(Date.now() / 1000 + 7 * 24 * 60 * 60),
          // I just create a custom object
          "roles": {
            "allowed-roles": ["user", "admin"],
            "default-role": "user",
            // you could decide the role based on email or userId. write your logic
            "role":"user"
          },
        },
        process.env.JWT_SECRET
      );
      // set the token
      setTokenCookie(token, res);
      res.send({ done: true });
    } catch (error) {
      console.error("Something went wrong logging in", error);
      res.status(500).send({ done: false });
    }
  } else {
    res.send({ done: false });
  }
}

2- write a set cookie function used in above api function

import cookie from "cookie";

const MAX_AGE = 7 * 24 * 60 * 60;

export const setTokenCookie = (token, res) => {
  const setCookie = cookie.serialize("token", token, {
    maxAge: MAX_AGE,
    expires: new Date(Date.now() + MAX_AGE * 1000),
    secure: process.env.NODE_ENV === "production",
    path: "/",
  });
  res.setHeader("Set-Cookie", setCookie);
};

3- write a verify token function

import jwt from "jsonwebtoken";

export async function verifyToken(token) {
  if (token) {
    const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
    console.log("decodedToken",decodedToken)
    // get the token role from decodedToken
    const userId = decodedToken?.issuer;
    return {userId,role};
  }
  return null;
}

4- Finally in _middleware.js function:

export async function middleware(req, ev) {
  console.log("ev in middleware", ev);
  const token = req ? req.cookies?.token : null;
  const {userId,role} = await verifyToken(token);
  // got the role and add logic for role
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Yilmaz