MSAL Authentication in React: Complete Guide – Part 3: Protected Routes and Route Guards

MSAL Authentication in React: Complete Guide – Part 3: Protected Routes and Route Guards

This entry is part 3 of 5 in the series Mastering MSAL Authentication in React Applications

Welcome to Part 3 of our MSAL authentication series! Now that we have our authentication provider set up, let’s implement protected routes and route guards to secure specific pages in your React application.

Understanding Protected Routes

Protected routes ensure that only authenticated users can access certain pages of your application. They act as gatekeepers, redirecting unauthenticated users to login pages or showing appropriate messages.

Types of Route Protection

  • Authentication-based: User must be logged in
  • Role-based: User must have specific roles or permissions
  • Conditional: Based on user attributes or application state

Setting Up React Router

First, install React Router if you haven’t already:

npm install react-router-dom

Set up your basic routing structure:

// src/App.js
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { AuthProvider } from './contexts/AuthContext';
import HomePage from './pages/HomePage';
import DashboardPage from './pages/DashboardPage';
import ProfilePage from './pages/ProfilePage';
import LoginPage from './pages/LoginPage';
import ProtectedRoute from './components/ProtectedRoute';
import Navigation from './components/Navigation';

function App() {
  return (
    <Router>
      <AuthProvider>
        <div className="app">
          <Navigation />
          <main className="main-content">
            <Routes>
              <Route path="/" element={<HomePage />} />
              <Route path="/login" element={<LoginPage />} />
              <Route 
                path="/dashboard" 
                element={
                  <ProtectedRoute>
                    <DashboardPage />
                  </ProtectedRoute>
                } 
              />
              <Route 
                path="/profile" 
                element={
                  <ProtectedRoute>
                    <ProfilePage />
                  </ProtectedRoute>
                } 
              />
            </Routes>
          </main>
        </div>
      </AuthProvider>
    </Router>
  );
}

export default App;

Creating a Protected Route Component

Let’s create a reusable ProtectedRoute component that handles authentication checks:

// src/components/ProtectedRoute.js
import React from 'react';
import { Navigate, useLocation } from 'react-router-dom';
import { useIsAuthenticated, useMsal } from '@azure/msal-react';
import LoadingSpinner from './LoadingSpinner';

const ProtectedRoute = ({ 
  children, 
  redirectTo = '/login',
  requiredRoles = [],
  fallback = null 
}) => {
  const isAuthenticated = useIsAuthenticated();
  const { inProgress, accounts } = useMsal();
  const location = useLocation();

  // Show loading during authentication process
  if (inProgress === "login" || inProgress === "startup") {
    return <LoadingSpinner message="Checking authentication..." />;
  }

  // If not authenticated, redirect to login with return URL
  if (!isAuthenticated) {
    return <Navigate 
      to={redirectTo} 
      state={{ from: location }} 
      replace 
    />;
  }

  // Check role-based access if required roles are specified
  if (requiredRoles.length > 0 && accounts.length > 0) {
    const userRoles = accounts[0]?.idTokenClaims?.roles || [];
    const hasRequiredRole = requiredRoles.some(role => 
      userRoles.includes(role)
    );
    
    if (!hasRequiredRole) {
      return fallback || (
        <div className="access-denied">
          <h2>Access Denied</h2>
          <p>You don't have permission to access this page.</p>
        </div>
      );
    }
  }

  // Render protected content
  return children;
};

export default ProtectedRoute;

Advanced Route Guards

For more complex scenarios, let’s create specialized route guards:

Role-Based Route Guard

// src/components/RoleGuard.js
import React from 'react';
import { useMsal } from '@azure/msal-react';

const RoleGuard = ({ 
  children, 
  allowedRoles = [], 
  fallback = null,
  mode = 'any' // 'any' or 'all'
}) => {
  const { accounts } = useMsal();
  
  if (accounts.length === 0) {
    return fallback || <div>No account information available.</div>;
  }

  const userRoles = accounts[0]?.idTokenClaims?.roles || [];
  
  let hasAccess = false;
  
  if (mode === 'any') {
    // User needs at least one of the allowed roles
    hasAccess = allowedRoles.some(role => userRoles.includes(role));
  } else if (mode === 'all') {
    // User needs all of the allowed roles
    hasAccess = allowedRoles.every(role => userRoles.includes(role));
  }

  if (!hasAccess) {
    return fallback || (
      <div className="insufficient-permissions">
        <h3>Insufficient Permissions</h3>
        <p>You need the following roles: {allowedRoles.join(', ')}</p>
        <p>Your roles: {userRoles.join(', ') || 'None'}</p>
      </div>
    );
  }

  return children;
};

export default RoleGuard;

What’s Next?

In Part 4, we’ll focus on token management and API calls. We’ll cover:

  • Acquiring access tokens silently
  • Making authenticated API calls
  • Handling token refresh
  • Token caching strategies

Continue following this series to master MSAL authentication in your React applications!

Navigate<< MSAL Authentication in React: Complete Guide – Part 2: MSAL Provider and Authentication ContextMSAL Authentication in React: Complete Guide – Part 4: Token Management and API Calls >>

Written by:

265 Posts

View All Posts
Follow Me :
How to whitelist website on AdBlocker?

How to whitelist website on AdBlocker?

  1. 1 Click on the AdBlock Plus icon on the top right corner of your browser
  2. 2 Click on "Enabled on this site" from the AdBlock Plus option
  3. 3 Refresh the page and start browsing the site