1

I am following the instructions here to use Auth0 with react-router-dom V6 and so far I am able to get it working with the basic routes.

Now I am trying to make it work with components which accept props and I not sure how to pass in the props correctly. This is the code for the ProtectedRoute

import React, { ComponentType } from 'react';
import { withAuthenticationRequired } from '@auth0/auth0-react';
import { Loading } from './Loading';

interface ProtectedRouteProps {
  component: ComponentType,
  props: any
}

export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
  component, props
}) => {
  const Component = withAuthenticationRequired(component, {
    onRedirecting: () => <Loading />,
  });

  return <Component {...props} />;
};

And I am setting up the basic route component as

<Route path="/" element={<ProtectedRoute component={Dashboard} />}/>

My Dashboard element expects a prop of say type string and name testProp. What would be the right way to pass it in? I have tried the following but none of them work correctly.

<Route path="/" element={<ProtectedRoute component={Dashboard} testProp={"test"} />}/>

<Route path="/" element={<ProtectedRoute component={Dashboard} props={{testProp: "test"}} />}/>

Can someone please provide an example of how to forward the props to the ProtectedRoute so that it can be used as a generic wrapper? I am new to react and typescript and I am not able to figure out the right approach for this.

Edit:

With the second approach I get the following error in typescript

(property) ProtectedRouteProps.component: React.ComponentType<{}>
Type '({ testProp }: Props) => JSX.Element' is not assignable to type 'ComponentType<{}>'.
  Type '({ testProp }: Props) => JSX.Element' is not assignable to type 'FunctionComponent<{}>'.
    Types of parameters '__0' and 'props' are incompatible.
      Property 'testProp' is missing in type '{ children?: ReactNode; }' but required in type 'Props'.ts(2322)
avocado
  • 79
  • 9
  • The second method (`}/>`) appears to be the correct way to pass the dashboard props through on the `ProtectedRoute`'s `props` prop. This is an odd `ProtectedRoute` component... it will create a new `Component` each time the routes render, having the effect of remounting the component you are trying to protect. This might not be ideal, but it seems to be the way auth0 says to integrate with `react-router-dom`. – Drew Reese Apr 04 '22 at 22:47
  • @DrewReese I tried the second approach but I get the compilation error which I have listed in the Edit section of the question above. The component gets converted into an element when we setup the props. – avocado Apr 07 '22 at 04:39
  • The second approach works but it just seems like a typing issue. Unfortunately I'm not well-versed in TS. Do you need this `ProtectedRoute` component at all though? Why not just decorate the components that need the auth check? Something like `const DashboardWithAuth = withAuthenticationRequired(Dashboard, { onRedirecting: Loading });` and then in the `Route` and `element={}`. – Drew Reese Apr 07 '22 at 05:40
  • @DrewReese Yes that is an approach which should work but (1) I will have to do that for every route separately which is cumbersome if the number of routes are too many. I can make a generic wrapper for this. (2) This is pretty close to what Auth0 has already and I might again run into not being able to pass in the props. Thanks for the input though. I will try out these ideas soon and let you know once I solve it. – avocado Apr 07 '22 at 17:16
  • You are already using `ProtectedRoute` on each route, so I don't see much of a distinction between the two against your first point. It's actually why I suggested it. For point two, like I said... their implementation of a private route is a little odd and will unnecessarily remount protected components. It seems you're at a weird crossroad of needing to use and mix an HOC with a Wrapper component that is the preferred method in RRDv6. RRDv6 *actually* further prefers using layout routes for a single auth check and rendering the routes you want to protect into an `Outlet` component. – Drew Reese Apr 07 '22 at 18:31
  • Here's an [answer](https://stackoverflow.com/a/66289280/8690857) of mine that shows the difference between v5 and v6 protected routes. It might help you think of a different/improved way to protect your routes than the HOC in a wrapper. I didn't look over more of the auth0 docs, but they may have other non-HOC ways to do the auth checks. – Drew Reese Apr 07 '22 at 18:36

1 Answers1

0

Sorry for responding so late to this post, but I have not been able to find a suitable answer, but managed to work it out.

I didn't use interfaces, but I'm sure you could easily change it to use them. All my routes are being sent to an Outlet.

Try this: ProtectedRoute definition in the parent component:

const ProtectedRoute: React.FC<{ component: React.FC<{ testProp: string }>; testProp: string; }> =
    ({ component, testProp }) =>
    {
        const Component: React.FC<{ testProp: string; }> =
            withAuthenticationRequired(component);

    return <Component testProp={testProp} />;
};

if you want to use the ProtectedRoute for routes that do not use the prop, make it optional and use the non-mull assertion (!) in the child component example below:

const ProtectedRoute: React.FC<{ component: React.FC<{ testProp?: string }>; testProp?: string; }> =
    ({ component, testProp }) =>
    {
        const Component: React.FC<{ testProp?: string; }> =
            withAuthenticationRequired(component);

    return <Component testProp={testProp} />;
};

The Route (no change if you use optional parameters or not):

<Route path='/' element={<ProtectedRoute component={Dashboard} testProp={testProp} />} />

The Dashboard:

...your stuff here

const Dashboard: React.FC<{testProp: string; }> = ({testProp}) => { 
    const newVal = testProp;

    ...your stuff here...
};
    
export default Dashboard;

using the optional parameter

...your stuff here

const Dashboard: React.FC<{testProp?: string; }> = ({testProp}) => { 
    const newVal = testProp!;

    ...your stuff here...
};
    
export default Dashboard;