auth0next.js14nextjs-dynamic-routing

User authentication + dynamic routing problems (Auth0 & next.js App Router)


I have the basic Auth0 setup with app/api/[auth0]/route.ts and so users can log in/out but there is no validation to check and redirect a user to the start page if they haven't logged in.

So I've been trying to integrate some sort of user-authentication on my profile page. But my profile (app/user-dashboard/[user_id]/page.tsx) page is configured with dynamic routing like so:

export async function generateMetadata({
  params,
}: {
  params: { user_id: string };
}) {
  return {
    title: 'User Dashboard',
    description: `Dashboard for User: ${params.user_id}`,
  };
}
const UserDashboard = ({ params }: { params: { user_id: string } }) => {
 ... rest of page

Very similar to how nextjs docs explain in it nextjs.org. And I've tried to implement "withPageAuthRequired" on this page: like so:

... rest of user page above.
export default withPageAuthRequired(UserDashboard, {
  returnTo: ({ params }: AppRouterPageRouteOpts) => {
    if (params) {
      const user_id = params['user_id'];
      if (typeof user_id === 'string') {
        return `${process.env.NEXT_PUBLIC_BASE_URL}/user-dashboard/${user_id}`
      }
    }
  }
});

But I get some typescript error on "UserDashboard":

Argument of type '({ params }: {    params: {        user_id: string;    };}) => React.JSX.Element' is not assignable to parameter of type 'AppRouterPageRoute'.
  Types of parameters '__0' and 'obj' are incompatible.
    Type 'AppRouterPageRouteOpts' is not assignable to type '{ params: { user_id: string; }; }'.
      Types of property 'params' are incompatible.
        Type 'Record<string, string | string[]> | undefined' is not assignable to type '{ user_id: string; }'.
          Type 'undefined' is not assignable to type '{ user_id: string; }'.ts(2345)
const UserDashboard: ({ params }: {
    params: {
        user_id: string;
    };
}) => React.JSX.Element

I'm very new to Auth0 and so I'm not sure if I should try to use "withPageAuthRequired" to check whether a user is logged in or not. I find the documentation very abstract.

Have anyone had this issue before and know what to do?

In Summary, tried this:

export default withPageAuthRequired(UserDashboard, {
  returnTo: ({ params }: AppRouterPageRouteOpts) => {
    if (params) {
      const user_id = params['user_id'];
      if (typeof user_id === 'string') {
        return `${process.env.NEXT_PUBLIC_BASE_URL}/user-dashboard/${user_id}`
      }
    }
  }
});

And expected some validation to happen that checks if user i logged in and returns them to the user page or log in page.


Solution

  • After taking the advice on using Zod and trying out different things I found that this solution worked for my needs:

    const UserDashboardSchema = z.object({
      user_id: z.string(),
    });
    
    type UserParams = z.infer<typeof UserDashboardSchema>;
    
    const UserDashboard: (
      obj: AppRouterPageRouteOpts,
    ) => Promise<React.ReactElement> = async ({ params }) => {
      if (!params || !('user_id' in params)) {
        redirect(`${process.env.NEXT_PUBLIC_BASE_URL}/`);
      }
    ... rest of page component.
    

    And before exporting the page I had to make sure it was (and had the correct props) of the same type as needed by AppRouterPageRouteOpts:

    export default withPageAuthRequired(UserDashboard, {
      returnTo: (obj: AppRouterPageRouteOpts) => {
        if (obj && obj.params && 'user_id' in obj.params) {
          const { user_id } = obj.params;
          return `${process.env.NEXT_PUBLIC_BASE_URL}/user-dashboard/${user_id}`;
        }
        return `${process.env.NEXT_PUBLIC_BASE_URL}/`;
      },
    });