Next.js Discord

Discord Forum

Next.js 14 App Layout + Server Actions + Protected Routes

Answered
pheralb posted this in #help-forum
Open in Discord
Avatar
Hi! I have the following structure:
πŸ“ app
 | πŸ“ [user]
   | βš›οΈ layout.tsx
   | βš›οΈ page.tsx
 | βš›οΈ layout.tsx
 | βš›οΈ page.tsx

In the app/page.tsx, I'm using Server Actions to redirect when the user is signed in:
// πŸ“ app/page.tsx
const user = await getUser();

if (user) {
   return redirect(`/${user.user_metadata.user_name}`);
}

My question is as follows. I am using app/[user]/layout.tsx to protect paths that are [user]/*:
// πŸ“ app/[user]/layout.tsx
import { getUserData } from "@/server/auth";
import { redirect } from "next/navigation";

const AppLayout = async ({ params }: { params: { user: string } }) => {
  const user = await getUserData(params.user);

  if (!user) {
    return redirect("/auth");
  }
  
  return <div>AppLayout</div>;
};

export default AppLayout;

The app works but I am not clear if it is the right way. Taking into account that the app has multiple protected pages. πŸ€”

- getUserData It's a server action that checks if the user is logged in and if the path.user matches the Supabase getUser username:
export const getUserData = async (username: string) => {
  const user = await getUser();
  if (!user) {
    return redirect("/auth");
  }
  if (user.user_metadata.user_name !== username) {
    return redirect(`/${user.user_metadata.user_name}`);
  }
  return user;
};
Answered by B33fb0n3
your middleware right now only updates the session. Right now, it does not handle the auth process. As I said: If I would be you, I would let my middleware handle the auth process to protect specific routes
View full answer

11 Replies

Avatar
@pheralb Hi! I have the following structure: πŸ“ app | πŸ“ [user] | βš›οΈ layout.tsx | βš›οΈ page.tsx | βš›οΈ layout.tsx | βš›οΈ page.tsx In the ``app/page.tsx``, I'm using Server Actions to redirect when the user is signed in: tsx // πŸ“ app/page.tsx const user = await getUser(); if (user) { return redirect(`/${user.user_metadata.user_name}`); } My question is as follows. I am using ``app/[user]/layout.tsx`` to protect paths that are ``[user]/*``: tsx // πŸ“ app/[user]/layout.tsx import { getUserData } from "@/server/auth"; import { redirect } from "next/navigation"; const AppLayout = async ({ params }: { params: { user: string } }) => { const user = await getUserData(params.user); if (!user) { return redirect("/auth"); } return <div>AppLayout</div>; }; export default AppLayout; The app works but I am not clear if it is the right way. Taking into account that the app has multiple protected pages. πŸ€” - ``getUserData`` It's a server action that checks if the user is logged in and if the path.user matches the Supabase getUser username: ts export const getUserData = async (username: string) => { const user = await getUser(); if (!user) { return redirect("/auth"); } if (user.user_metadata.user_name !== username) { return redirect(`/${user.user_metadata.user_name}`); } return user; };
Avatar
If I need to protect data, then I would verify and authenticate my user inside my middleware and check only protected routes thought middleware. The middleware is handled on edge and serverside, so I am able to retrieve the data without a server action.

You might want to do the same, the secure your pages
Avatar
@B33fb0n3 If I need to protect data, then I would verify and authenticate my user inside my middleware and check only protected routes thought middleware. The middleware is handled on edge and serverside, so I am able to retrieve the data without a server action. You might want to do the same, the secure your pages
Avatar
Hii! I'm using the Supabase middleware:
- https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs?queryGroups=language&language=ts#nextjs-middleware
import { type NextRequest } from "next/server";
import { updateSession } from "@/server/supabaseMiddleware";

export async function middleware(request: NextRequest) {
  return await updateSession(request);
}

export const config = {
  matcher: [
    "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
  ],
};

If I use the following in my [user]/layout.tsx:
import { getUserData } from "@/server/auth";

const AppLayout = async ({ params }: { params: { user: string } }) => {
  const user = await getUserData(params.user);
  return <div>{user.user_metadata.name}</div>;
};

export default AppLayout;

and my getUserData:
export const getUserData = async (username: string) => {
  const user = await getUser();
  if (!user) {
    return redirect("/auth");
  }
  if (user.user_metadata.user_name !== username) {
    return redirect(`/${user.user_metadata.user_name}`);
  }
  return user;
};

Would it be well implemented? πŸ€”
I would be protecting and doing the redirect directly from the layout
Answer
Avatar
@pheralb Oh ok, I got it. Thank you very much πŸ˜„
Avatar
does that information solved your problem? πŸ˜„
Avatar
@pheralb ?
Avatar
Hii @B33fb0n3 πŸ˜„

In the end, I managed to solve it using Next.js middleware and looking at a Supabase example on Github. Thank you very much for your help!
Authentication and route protection worked great πŸ₯³
Avatar
@B33fb0n3 sure thing. Please mark solution
Avatar
Ready πŸš€
Avatar