npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

auth-react-router

v0.4.7

Published

**`auth-react-router`** is a package that wraps over `react-router-dom` v6 and allows you, to easily define the routes, based on user authorized (`isAuth`) and role (`userRole`) state. It provides a simple API for configuring `public`, `private` and `comm

Downloads

104

Readme

auth-react-router is a package that wraps over react-router-dom v6 and allows you, to easily define the routes, based on user authorized (isAuth) and role (userRole) state. It provides a simple API for configuring public, private and common routes (React suspense ready) and it has a simple and advance RBAC configuration.

This code and route pattern is used on most of the projects and would probably meet all the routing requirement for an actual react application.

Note: react-router-dom version >= 6 is required

Getting Started

Define your application routes *(easier to maintain if are in separate file)

// routes.tsx

import React from 'react';
import { IRoutesConfig } from 'auth-react-router';
import LoginPage from '../pages/LoginPage.tsx';

// public lazy loaded pages
const LazyPublicPage = React.lazy(() => import('../pages/PublicPage.tsx'));

// private lazy loaded pages
const LazyPrivatePage = React.lazy(() => import('../pages/PrivatePage.tsx'));
const LazyProfilePage = React.lazy(() => import('../pages/ProfilePage.tsx'));

// define some roles if RBAC is needed
export const roles = {
  ADMIN: 'ADMIN',
  OPERATION: 'OPERATION',
  MANAGER: 'MANAGER',
  REGULAR: 'REGULAR',
};

// routes definition
export const routes: IRoutesConfig = {
  publicRedirectRoute: '/profile', // redirect to `/profile` when authorized is trying to access public routes
  privateRedirectRoute: '/login', // redirect to `/login` when unauthorized user access a private route
  defaultFallback: <MyCustomSpinner />,
  // if the role of the user (`userRole` props) is not contained in the route `roles`
  InvalidUserRoleFallback: ({ currentUserRole, routeRequiredRoles }) => <p>USER HAS NO PERMISSION FOR THIS ROUTE, current user role is {currentUserRole}, required roles: {JSON.stringify(routeRequiredRoles)}</p>,
  public: [
    {
      path: '/public',
      component: <LazyPublicPage />
    },
    {
      path: '/login',
      component: <LoginPage />,
    },
  ],
  private: [
    {
      path: '/private',
      component: <LazyPrivatePage />,
      // role based routing
      // user must have ONE of the bellow roles
      roles: [roles.ADMIN, roles.MANAGER] 
    },
    {
      path: '/profile',
      component: <LazyProfilePage /> // any autorized user can access this route
    },
    {
      path: '/admin_and_operation',
      roles: [roles.ADMIN, roles.OPERATION], 
      allRolesRequired: true, // user must have ADMIN and OPERATION role to access this route
      component: <h1>ADMIN and OPERATION Page</h1>,
    },
    // nested routes example
    {
      path: '/posts',
      component: <>
        <h1>Posts Lists Layout</h1>
        <Outlet/> {/* render outlet (the matched paths) */}
      </>,
      children: [
        {
          index: true,
          component: <h1>a list of posts here...</h1>
        },
        {
          path: 'create',
          component: <h1>create new post</h1>
    	},
        {
          path: ':id',
          component: <>
            Single post page layout
            <Outlet/>
          </>,
          children: [
            {
              index: true,
              component: <h1>post details</h1>
            },
            {
              path: 'update',
              component: <h1>update post with dynamic :id</h1>
            }
          ]
        }
      ]
    }
  ],
  common: [
    {
      path: '/',
      component: <p>common</p>,
    },
    {
      path: '*',
      component: <p>page not found 404</p>,
    },
  ],
};

Link the defined above routes using AppRouter component

import { AppRouter, Routes } from 'auth-react-router';
import { BrowserRouter } from 'react-router-dom';
import { routes, roles } from './routes';

export const App = () => {
  const { isAuth } = useAuthProvider();
  return (
    <BrowserRouter>
      {/* `userRole` is optional, use it only if at least one Route has the `roles` property */}
      {/* `userRole` can be an array of roles too, usually you will fetch it from an API and set it here */}
      <AppRouter isAuth={isAuth} routes={routes} userRole={roles.ADMIN}>
        {/* Wrap `Routes` component into a Layout component or add Header */}
        <Routes />
      </AppRouter>
    </BrowserRouter>
  );
};

That is it, super easy!

To add a new route just add it to public, private or common array and it will work.

Check out example directory for a demo application (includes all most of the described features).

$ git clone https://github.com/nichitaa/auth-react-router # clone repo
$ npm i # install library dependencies
$ npm start # build the library `dist` folder

$ cd example
$ npm i # install demo app dependencies 
$ npm run dev # see live changes for demo app

Hooks

useCheckRole

Validate current user role with some given roles. This way is easy to dynamically render the UI, block or allow some of your application functionalities in dependence with user role.

useCheckRole arguments:

requiredRoles: string | string[]; // role/roles to check against 
allRolesRequired?: boolean; // if user must have all roles to have access to resource

useCheckRole return:

interface IUseCheckRoleReturn {
  isAllowed?: boolean; // eighter user has required permission or not
  userRole?: string[] | string; // current user permission
}

usage:

const Component = () => {
  const { isAllowed, userRole } = useCheckRole(roles.OPERATION);
  // render UI based on isAllowed flag
  return <h1>Component {isAllowed && <p>and isAllowed</p>}</h1>;
};
const Component = () => {
  const { isAllowed, userRole } = useCheckRole(['OPERATION', 'ADMIN']); // should have only one of them
  return <h1>Component {isAllowed && <p>and isAllowed</p>}</h1>;
};
const Component = () => {
  const { isAllowed, userRole } = useCheckRole(['OPERATION', 'ADMIN'], true); // should have both roles
  return <h1>Component {isAllowed && <p>and isAllowed</p>}</h1>;
};

Router / Routes basic configuration

AppRouter Provider interface

export interface IRouterContextProps {
  /** routes configuration */
  routes: IRoutesConfig;

  /** authorization state of the user, if not provided only `common` routes will work correspondingly */
  isAuth?: boolean;

  /** current user role that will be validated for accessing a specific route */
  userRole?: string;
}

routes configuration interface

export interface IRoutesConfig {
  /**
   * defaults to `/`
   * authorized users on public routes will be redirected to this route
   */
  privateRedirectRoute?: string;

  /**
   * defaults to `/`
   * unauthorized users on private routes will be redirected to this route
   */
  publicRedirectRoute?: string;

  /** default fallback component for lazy loaded route components */
  defaultFallback?: React.ReactElement;

  /** fallback component in case the user does not have the required role to access the route */
  InvalidUserRoleFallback?: React.ComponentType<any>

  /** private routes are accessible only by authorized users */
  private?: IRoute[];

  /** public routes are accessible only by unauthorized users */
  public?: IRoute[];

  /** common routes are accessible only by authorized and unauthorized users */
  common?: IRoute[];
}

single route interface IRoute

export interface IRoute {
  /** a valid react-router-dom v6 path */
  path?: string;

  /** the component to be rendered under the path */
  component: React.ReactElement;
    
  /** if this is a route definition for index path */
  index?: boolean;
   
  /** used for nested (aka children) routes definition */
  children?: IRoute[];

  /**
   * if route component is lazy loaded using React.lazy() a fallback loading / spinner component can be specified
   * it has higher priority then the `defaultFallback` component
   * */
  fallback?: React.ReactElement;

  /**
   * what roles a user must have in order to view this page,
   * if not provided, then the page can be accessed by every user
   */
  roles?: string[];
    
  /**
   * user must have all roles from `roles` array to access the route,
   * defaults to `false` 
   */
  allRolesRequired?: boolean;
}