Next.js Discord

Discord Forum

Checking twice for userId with auth or once?

Answered
Amorph posted this in #help-forum
Open in Discord
this is my function inside my DAL file:
export async function getStoreByUserAndStoreId(
  userId: string,
  storeId: string
) {
  const store = await prisma.store.findFirst({
    where: {
      id: storeId,
      userId,
    },
  });

  return store;
}


this is the only layout page that uses the function and the only place that will redirect if there is no userId:
import Navbar from "@/components/navbar";
import { getStoreByUserAndStoreId } from "@/server/data-access-layer";
import { auth } from "@clerk/nextjs/server";
import { redirect } from "next/navigation";

export default async function DashboardLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: { storeId: string };
}) {
  const { userId } = auth();
  if (!userId) redirect("/sign-in");

  const store = await getStoreByUserAndStoreId(userId, params.storeId);

  if (!store) redirect("/");

  return (
    <>
      <Navbar />
      {children}
    </>
  );
}
Answered by B33fb0n3
you shouldn't check your auth inside your layout. The user can still access the content and your layout leak. It's more described here: https://github.com/eric-burel/securing-rsc-layout-leak

Solutions:
checking authentication in a middleware
checking authentication in the page
checking authentication in the data fetching method

In your case I guess the best solution is checking it inside the middleware
View full answer

5 Replies

And this is one of my route handlers but they pretty much share the same logic and checks so i'll only post one of them:
export async function POST(
  request: Request,
  { params }: { params: { storeId: string } }
) {
  try {
    const { userId } = auth();
    const body = await request.json();
    const { label, imageUrl } = body;

    if (!userId) return new NextResponse("Unauthenticated", { status: 401 });

    if (!label) return new NextResponse("Label is required", { status: 400 });

    if (!imageUrl)
      return new NextResponse("Image URL is required", { status: 400 });

    if (!params.storeId)
      return new NextResponse("Store id is required", { status: 400 });

    // confirm that this storeId exists for this user
    const storeByUserAndStoreId = await getStoreByUserAndStoreId(
      userId,
      params.storeId
    );

    // if the store id in combination with the user id is not available, that means the user is trying to update someone elses store
    if (!storeByUserAndStoreId)
      return new NextResponse("Unauthorized", { status: 403 });

    const heroImage = await createHeroImage(label, imageUrl, params.storeId);

    return NextResponse.json(heroImage);
  } catch (error) {
    console.log("[HEROIMAGES_POST]", error);
    return new NextResponse("Internal error", { status: 500 });
  }
}


I want to move, from all my route handlers into my DAL file, the part that checks for an user id and if there is no user id then error will be thrown, that implicitly meaning also removing the userId as an argument from the function, but there is the layout page where i want to do a redirect if there is no user id and i'm not sure how to approach this part. i can't move the redirect inside the function so only option i see is for layout i'll double check for userid, once in the layout and once when the function is called, is there a better way to approach this?
Answer
Sure thing