Skip to content

fix(auth): prevent unauthorized role-based redirects on login

Overview

This MR fixes a critical routing bug where a user logging out of a role-restricted page would leave that URL in the router's state.from history, incorrectly redirecting the next logged-in user to that unauthorized page. It also resolves an unmounted component state update memory leak in NotificationContext that was causing the Vitest pre-commit hooks to fail.

What does this MR do and why?

Motivation: If an admin logged out while on /admin/medical-camps, the application preserved that location in state.from. If a volunteer then logged in on the same browser tab, they were incorrectly redirected to the admin page because ProtectedRoute only verified if a user was authenticated without actively checking their specific role. Additionally, test suites were failing due to a ReferenceError: window is not defined inside NotificationContext.

Approach:

  1. Modified ProtectedRoute to actively check user.roles against the requested URL prefix (/admin, /volunteer, /coordinator) and immediately redirect unauthorized users to the home dashboard (/).
  2. Modified NotificationContext to track notification timeouts in a useRef and explicitly clearTimeout on them when the NotificationProvider unmounts, fixing the unmounted state update issue during test teardowns.

Changes Made

Technical Details

  • Routing Issue: The root cause was that ProtectedRoute allowed any authenticated user to pass. By adopting a .startsWith() string matching approach on location.pathname, we securely scale to nested paths (e.g., /admin/manage-doctors) without heavy refactoring.
  • Test Error Issue: The Vitest window is not defined error was caused by setTimeout firing 5 seconds after the React Testing Library had already torn down the DOM environment. By registering the NodeJS.Timeout IDs in a ref, we forcefully clear them on unmount.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 📝 Documentation update
  • 🎨 UI/UX improvement
  • ️ Refactor (no functional changes)
  • Performance improvement
  • 🧪 Test update
  • 🔧 Configuration change
  • 🚨 Security fix

Related Issues / References

  • Closes #246 (closed)

  • Resolves the cross-role routing redirection bug.

  • Resolves the husky pre-commit vitest failure.

Screenshots or Screen Recordings

Before: Screencast_from_2026-03-22_12-08-36 After: Screencast_from_2026-03-24_15-32-03

How to Set Up and Validate Locally

  1. Pull this branch / checkout the MR.
  2. Run development server: bash npm run dev 3.Log in as an Admin. Navigate to an admin page like http://localhost:5173/admin/medical-camps
  3. Log out using the sidebar. You will be redirected to /login.
  4. Without refreshing or closing the tab, log in as a Volunteer.
  5. Expected behavior: You should not see the admin page. The app will intercept the disallowed

Testing Done

Test Cases Covered:

Scenario Expected Result Status
Admin logs out -> Volunteer logs in Volunteer redirected to /, not /admin/*
Admin attempts access to /volunteer/* Admin cleanly redirected to /

|
NotificationContext.test.tsx Memory Leak | Test passes without unmounted window undefined error | |

Code Quality Checklist

Code Standards

  • Code follows project conventions (naming, structure, formatting)
  • No console.log() or debugger statements left in code
  • No unused imports, variables, or functions
  • No duplicate code and use of existing components for reusability
  • i18n check passed with no hardcoded strings in codebase for i18n support
  • TypeScript types are properly defined (no any unless justified)
  • ESLint and Prettier checks pass
    bun run lint

React Best Practices

  • Components are properly split and single-responsibility
  • Hooks follow rules (no conditional hooks, proper dependencies)
  • State management is appropriate (local vs global state)
  • No unnecessary re-renders (memoization used where needed)
  • Event handlers are properly cleaned up

Component Patterns

  • shadcn/ui components used correctly
  • Tailwind classes follow utility-first approach
  • Responsive design considered (mobile-first if applicable)
  • Accessibility attributes included (aria-*, role, etc.)
  • Icons from lucide-react used consistently

API & Data Fetching

  • TanStack Query used for server state (if applicable)
  • Loading and error states handled
  • API types defined in src/types/api.ts
  • Axios interceptors handle auth tokens correctly
  • Use of Zod for data validations

Error Handling

  • Errors are caught and handled gracefully
  • User-friendly error messages displayed
  • Errors are being toasted properly
  • Network failures handled appropriately

Documentation

  • README.md updated (if setup steps changed)
  • .env.example updated (if new env vars added)
  • CHANGELOG.md updated (if applicable)

Known Limitations / Technical Debt

Additional Notes


MR Acceptance Checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Bikkumalla Sai Krishna

Merge request reports

Loading