Authentication & Authorization

Implementing Authentication for Each Page/Route

In this guide, we will walk you through the steps to implement authentication in your Jumbo React template. Jumbo provides various tools and components to simplify the process of securing your application. The authentication implementation can be broken down into the following steps:

1. AuthProvider

Jumbo offers an AuthProvider component that utilizes the Context API. This component provides four key values: isAuthenticated, loading, login, and logout. These values can be accessed using the useAuth hook as shown below:

javascriptCopy codeconst { isAuthenticated, loading, login, logout } = useAuth();
  • isAuthenticated: A boolean indicating if the user is authenticated.

  • loading: A boolean indicating if the authentication state is being determined.

  • login: A handler to log the user in.

  • logout: A handler to log the user out.

Usage Example:

typescriptCopy code// AuthContext.tsx
import React, { createContext, useContext, useState, ReactNode, FC } from 'react';

interface AuthContextType {
  isAuthenticated: boolean;
  loading: boolean;
  login: () => void;
  logout: () => void;
  authUser?: any; // Add this if you want to provide user information
}

const AuthContext = createContext<AuthContextType | null>(null);

export const AuthProvider: FC<{ children: ReactNode }> = ({ children }) => {
  const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
  const [loading, setLoading] = useState<boolean>(false);
  const [authUser, setAuthUser] = useState<any>(null); // Manage user information

  const login = () => {
    setLoading(true);
    // Add your login logic here
    setIsAuthenticated(true);
    setAuthUser({ name: 'John Doe' }); // Example user info
    setLoading(false);
  };

  const logout = () => {
    // Add your logout logic here
    setIsAuthenticated(false);
    setAuthUser(null);
  };

  return (
    <AuthContext.Provider value={{ isAuthenticated, loading, login, logout, authUser }}>
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = (): AuthContextType => {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
};

This is the first place where you can place your logic and customize the login and logout handlers as per your project requirements. Additionally, you can export the authUser information to get full details of the authenticated user. The logic here can vary per project, so feel free to modify it to suit your needs.

2. Creating a HOC Function

In this step, you can create various Higher-Order Component (HOC) functions that act as middleware to apply authentication or authorization logic. Below is an example of an withAuth HOC function:

//File Name: @app/_hocs/withAuth.tsx

import { useAuth } from '@app/_components/_core/AuthProvider/hooks';
import Spinner from '@app/_shared/Spinner';
import React from 'react';
import { Navigate } from 'react-router-dom';

const withAuth = (Component: React.ComponentType) => {
  return (props: any) => {
    const { isAuthenticated, loading } = useAuth();
    if (loading) {
      return <Spinner />;
    }

    if (!isAuthenticated) {
      return <Navigate to="/auth/login-1" />;
    }

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

export default withAuth;

In the above example, the withAuth HOC function checks:

  • If authentication information is being pulled from cookies (loading: true), it returns a <Spinner />.

  • If loading is false and isAuthenticated is false, it considers the user not authenticated and redirects to the /auth/login-1 route.

  • Otherwise, it considers the user to be logged in and lets the request proceed to access the route.

Similarly, you can write other HOCs like withAdmin, withManager, etc., to manage authorization based on different roles.

3. Page Component

The Page component is used to define routes in your application. It accepts two props:

  • Component: The component to be rendered as a page.

  • hoc: The HOC function to be applied to the component.

Usage Example:

//File Name: @app/_components/_core/Page/Page.tsx

import React from 'react';

interface PageProps {
  Component: React.ComponentType;
  hoc?: (Component: React.ComponentType) => React.ComponentType;
}

const Page: React.FC<PageProps> = ({ Component, hoc }) => {
  const WrappedComponent = hoc ? hoc(Component) : Component;
  return <WrappedComponent />;
};

export default Page;

Defining Routes:

You can define routes and apply the HOC for authentication as follows:

//File Name: @app/_routes/index.tsx

import { RouteObject } from 'react-router-dom';
import StretchedLayout from '@app/layouts/StretchedLayout';
import MiscPage from '@app/pages/MiscPage';
import ListingPage from '@app/pages/ListingPage';
import Page from '@app/_components/_core/Page';
import withAuth from '@app/_components/_core/AuthProvider/withAuth';

const routes: RouteObject[] = [
  {
    path: '/',
    element: <StretchedLayout />,
    children: [
      {
        path: '/dashboards/misc',
        element: <Page Component={MiscPage} hoc={withAuth} />,
      },
      {
        path: '/dashboards/listing',
        element: <ListingPage />,
      },
    ],
  },
];

export default routes;

This setup provides flexibility in applying HOCs to implement authentication and authorization as per your project needs.

Last updated