skip to Main Content

I am making user role base protected routes in next.js in middleware.js but suddenly started getting this. Not sure why this happening if you guys have better way to implement that please let me know. Here is how I am doing so far by reading the documentation.

enter image description here

    import { getLoginUserDetail } from "@/actions/userActions/user";
    import { NextResponse } from "next/server";
    const customerProtectedRoute = ["/profile"];
    const disallowedLoggedInRoutes = ["/login", "/signup"];
    const adminProtectedRoute = [];

export async function middleware(request) {
  const user = await getLoginUserDetail(true);
  const path = request.nextUrl.pathname;
  console.log({ path });
  if (
    !user &&
    (customerProtectedRoute.find((el) => el.startsWith(path)) ||
      adminProtectedRoute.find((el) => el.startsWith(path)))
  ) {
    return NextResponse(new URL("/", request.url));
  }
 
  if (user && disallowedLoggedInRoutes.find((el) => el.startsWith(path))) {
    return NextResponse(new URL("/", request.url));
  }

  if (
    user?.role !== "super-admin" &&
    adminProtectedRoute.find((el) => el.startsWith(path))
  ) {
    return NextResponse(new URL("/", request.url));
  }
}

export const config = {
  // matcher: ['/about/:path*', '/dashboard/:path*'],
  matcher: ["/", "/profile", "/login", "/signup"],
};


// And Here is the code to fetch user detail in diffrent file
export const getLoginUserDetail = async (byMiddleware) => {
  try {
    const auth_token = getCookie("auth_token");
    if (!auth_token) {
      return null;
    }

    const headers = new Headers();
    headers.append("Content-Type", "application/json");
    headers.append("authorization", auth_token);
    const options = {
      method: "GET",
      headers: headers,
    };

    const response = await fetch(`${baseUrl}/api/v1/auth/account`, options);

    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }

    const data = await response.json();

    return data.user;
  } catch (error) {
    console.log({ error });
    return null;
  }
};

2

Answers


  1. Chosen as BEST ANSWER

    HERE is the code how I implement role based routing.

    I declare all route for logged in user first then for those route on which user can't go after login and then only admin routes.

    In the config I declare on which route it should be invoke. You may be thinking why I don't use the array over there but in next.js its saying it not permissible to there and start giving error. So either make regular expression for your use case (Which I am going to do) or pass every single route on which you wanna invoke that.

    I am using one getLoginUserDetail function where I am calling api to verify the user jwt token. Firstly I was calling api with axios then its started giving us adapter error because of some node its using under the hood as its my test project and don't have that much time so I do continue and use fetch instead which is working fine as its available in web and node as well.

    I am just adding this code for reference so may be it will help others

    https://nextjs.org/docs/app/building-your-application/routing/middleware

    import { getLoginUserDetail } from "@/actions/userActions/user";
    import { NextResponse } from "next/server";
    
    const customerProtectedRoute = ["/profile"];
    const disallowedLoggedInRoutes = ["/login", "/signup"];
    const adminProtectedRoute = [];
    
    export async function middleware(request) {
      const { host, protocol } = request.nextUrl;
      const user = await getLoginUserDetail(true);
      const path = request.nextUrl.pathname;
      console.log({ path, user });
      if (
        !user &&
        (customerProtectedRoute.find((el) => path.startsWith(el)) ||
          adminProtectedRoute.find((el) => path.startsWith(el)))
      ) {
        const url = new URL("/", `${protocol}//${host}`);
        return NextResponse.redirect(url);
      }
    
      if (user && !!disallowedLoggedInRoutes.find((el) => path.startsWith(el))) {
        const url = new URL("/", `${protocol}//${host}`);
        return NextResponse.redirect(url);
      }
    
      if (
        user?.role !== "super-admin" &&
        adminProtectedRoute.find((el) => path.startsWith(el))
      ) {
        const url = new URL("/", `${protocol}//${host}`);
        return NextResponse.redirect(url);
      }
    
      return NextResponse.next();
    }
    
    export const config = {
      // matcher: ['/about/:path*', '/dashboard/:path*'],
      matcher: ["/profile", "/login", "/signup"],
    };
    

  2. From looking at your code you are trying to redirect the user, but your call syntax is wrong, it should look like this instead:

    import { type NextRequest, NextResponse } from "next/server";
    
    export async function GET(request: NextRequest): Promise<NextResponse> {
      const { host, protocol } = request.nextUrl;
    
      const url = new URL("/", `${protocol}//${host}`);
    
      return NextResponse.redirect(url);
    }
    

    Furthermore to create a new NextResponse instance you would be missing the new keyword in front of the NextResponse call. You would call it like below instead, since NextResponse is a class object:

    const response = new NextResponse();
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search