React RBAC with Auth0

Viewed 374

I'm attempting to setup RBAC on the client-side using Auth0 ID token and a custom claim, but my app continues to return a type error.

Unhandled Rejection (TypeError): Cannot read property 'http://localhost:3000/roles' of undefined
▼ 2 stack frames were expanded.
getRoles
C:/Users/Logan/Documents/Development Projects/auth0 testing/testing/src/AuthorizeUser.js:14
async checkRoles
C:/Users/Logan/Documents/Development Projects/auth0 testing/testing/src/AuthorizeUser.js:17

It does not matter what route I try to navigate to for this to be thrown (protected or not) but I can make a change in the AuthorizeUser file, refresh the browser, and it will return to normal until the next time I refresh/click back. What is causing the useEffect to be undefined before it can even fire when not visiting a protected route? I set the useEffect up on a different component unrelated to the ProtectedRoute component and it worked fine - fired on page load, pulled the data I need and I was able to JSON.stringify it in a return statement to display it - without throwing any undefined errors.

I opened a ticket with Auth0 and received a helpful email that had a set of snippets that I based my code around (they were built with TypeScript which I'm not using in this project) so I restructured as necessary and as mentioned previously, it works fine when unrelated to the protected route component but once I placed it into this flow it continuously returns undefined.

Additionally, I tried to remove the return statement from the ProtectedRoute component, but that throws a "Nothing was returned from render." error even though I have the return statement in the AuthorizeUser component. What is causing this behavior or is this related to the undefined issue?

Index.js

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import { Auth0Provider } from "@auth0/auth0-react";

ReactDOM.render(
  <Auth0Provider
    domain={}
    clientId={}
    redirectUri={window.location.origin}
  >
      <App />
  </Auth0Provider>,
  document.getElementById("root")
);

App.js

import "./App.css";

import { BrowserRouter, Route } from "react-router-dom";
import Home from "./Home";
import User from "./User";
import Admin from "./Admin";
import NotAuthorized from "./NotAuthorized";
import { ProtectedRoute } from "./ProtectedRoute";

function App() {
  return (
    <BrowserRouter>
      <Route path="/" exact component={Home} />
      <ProtectedRoute path="/admin" role="Admin" component={Admin} />
      <ProtectedRoute path="/user" role="User" component={User} />
      <Route path="/not-authorized" component={NotAuthorized} />
    </BrowserRouter>
  );
}

export default App;

ProtectedRoute Component

import React from "react";
import { Route } from "react-router-dom";
import { withAuthenticationRequired } from "@auth0/auth0-react";
import { AuthorizeUser } from "./AuthorizeUser";
import Loader from "./Loader";

export const ProtectedRoute = ({ component, role, ...args }) => {
  return role ? (
    <Route
      component={withAuthenticationRequired(
        AuthorizeUser({ component, role }),
        {
          onRedirecting: () => <Loader />,
        }
      )}
      {...args}
    />
  ) : (
    <Route
      component={withAuthenticationRequired(component, {
        onRedirecting: () => <Loader />,
      })}
      {...args}
    />
  );
};

AuthorizeUser component

import React, { useEffect, useState } from "react";
import { useAuth0 } from "@auth0/auth0-react";
import { Redirect } from "react-router";

const roleClaimType = "http://localhost:3000/roles";

export const AuthorizeUser = ({ component: Component, role }) => {
  const [isAuthorized, setIsAuthorized] = useState(false);
  const { getIdTokenClaims } = useAuth0();

  useEffect(() => {
    async function getRoles() {
      const claims = await getIdTokenClaims();
      console.log(claims);
      return claims[roleClaimType] || [];
    }
    async function checkRoles() {
      const roles = await getRoles();
      console.log(roles);
      if (roles.includes(role)) {
        setIsAuthorized(true);
      }
    }
    checkRoles(role);
  }, [getIdTokenClaims]);

  return isAuthorized ? <Component /> : <Redirect to='/not-authorized'/>;
}
0 Answers
Related