Today I Learned

Tips for implementing RBAC in React

Implementing RBAC in React (Role-Based Access Control) means you will need to add logic in multiple components to check if user has the correct role to display part of the UI.

Here is how using HOC’s enables clean code.

step 1

The assumption is store user roles are stored in context or redux.

Create withRole HOC

export default const withRole = (roles) => (Component) => (props) => {
 const {userRoles} = useContext(userRoles)
 if (userRoles.match(roles)) {
  return <Component {props} />
 }
 return null
} 

step 2

This HOC can be easily applied on any component.

import Button from "./Button"
import Something from "./Something"

const RestrictedButton = withRole(['admin', 'manager'])(Button)
const RestrictedSomething = withRole(['editor'])(Something)

const SomeComponent = () => {
 return (
  <div>
    <RestrictedButton>Only admin and manager sees me</RestrictedButton>. 
    <RestrictedSomething someProp={someProp}/>
  </div>
)}

step 3

It’s useful to create helpers with already applied roles.

export const withAdminRole = withRole(['admin'])
export const withEditorRole = withRole(['editor'])
export const withManagmentRole = withRole(['admin', 'editor'])

and use them like that:

const RestrictedButton = withManagmentRole(Button)
const RestrictedSomething = withEditorRole(Something)

important

HOC’s should always be created outside of the components, to prevent them being recreated on every render.

const MyComponent = () => {
  // VERY BAD
  const EditorButton = withRole('editor')(Button)
  const AdminButton = withAdminRole(Button)
  return (
    <>
      <EditorButton />
      <AdminButton />
    </>
  )
}
// GOOD
const EditorButton = withRole('editor')(Button)
const AdminButton = withAdminRole(Button)
const MyComponent = () => {
  return (
    <>
      <EditorButton />
      <AdminButton />
    </>
  )
}