Commit b1a6de8a authored by Dimitrios Gogos's avatar Dimitrios Gogos
Browse files

feat: improve ProtectedRoute logic and add cache control headers

parent 9a99e6f6
Loading
Loading
Loading
Loading
+15 −10
Changes for portal-gui/src/app/guards/protected-route.tsx: 15 added lines, 10 removed lines.
Original line number Diff line number Diff line
import { useEffect, useState } from 'react';
import { useEffect } from 'react';
import { Navigate, Outlet, useLocation } from 'react-router-dom';
import { useAuth } from '@/features/auth/auth-context';
import { LoadingState } from '@/components/common/loading-state';
@@ -6,14 +6,22 @@ import { ROUTES } from '../config/route';
import { AuthPending } from './auth-pending';

const LAST_REDIRECT_KEY = 'portal:login-redirect-at';
// Coming back signed out sooner than this means the login did not stick, e.g. the
// session cookie is refused, and redirecting again would loop through Keycloak.
// A page loaded signed out this soon after our redirect is a login that did not
// stick, e.g. the session cookie is refused; redirecting again would loop.
const REDIRECT_COOLDOWN_MS = 10_000;

function redirectedRecently(): boolean {
function cameBackFromOwnRedirect(): boolean {
  const [arrival] = performance.getEntriesByType(
    'navigation',
  ) as PerformanceNavigationTiming[];
  // Back/Forward is the user's own navigation, whatever the timing.
  if (arrival?.type === 'back_forward') {
    return false;
  }
  try {
    const last = Number(sessionStorage.getItem(LAST_REDIRECT_KEY));
    return Date.now() - last < REDIRECT_COOLDOWN_MS;
    const mark = Number(sessionStorage.getItem(LAST_REDIRECT_KEY));
    const sinceMark = performance.timeOrigin - mark;
    return mark > 0 && sinceMark >= 0 && sinceMark < REDIRECT_COOLDOWN_MS;
  } catch {
    return false;
  }
@@ -34,13 +42,10 @@ function markRedirect(at: number | null) {
export function ProtectedRoute() {
  const { status, isAuthenticated, login } = useAuth();
  const location = useLocation();
  // Read once, on arrival: a page load straight after our own redirect is the
  // browser coming back from Keycloak.
  const [justRedirected] = useState(redirectedRecently);
  // Set by the login callback when it failed; redirecting again would repeat it.
  const error = new URLSearchParams(location.search).get('error');
  const signedOut = status === 'anonymous';
  const stuck = signedOut && !error && justRedirected;
  const stuck = signedOut && !error && cameBackFromOwnRedirect();
  const shouldRedirect = signedOut && !error && !stuck;
  const returnTo = location.pathname + location.search + location.hash;

+6 −0
Changes for portal-gui/vite.config.ts: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -14,6 +14,10 @@ export default defineConfig(({ mode }) => {
    },
  };

  // Keeps signed-in pages out of the back-forward cache: after a logout, Back would
  // otherwise show the old page's pixels before any script can hide them.
  const headers = { 'Cache-Control': 'no-store' };

  return {
    plugins: [react(), tailwindcss()],

@@ -28,10 +32,12 @@ export default defineConfig(({ mode }) => {
      port: 3000,
      strictPort: true,
      proxy,
      headers,
    },

    preview: {
      proxy,
      headers,
    },
  };
});