[SOLVED] Following a 301 Redirect from an API in a React App

Issue

This Content is from Stack Overflow. Question asked by HopAlongPolly

I’ve written a custom ProtectedRoute component for my React app that redirects a user to a /login route on my API if that user is not authenticated. The /login route returns a 301 Redirect to the Auth0 Universal Login UI.

I know the API /login route works because I can hit it directly I get redirected to the Auth0 workflow.

I also know the ProtectedRoute is redirecting correctly because localhost:3000/api/login, which is the correct API route, shows up in the address bar but the redirect to the Auth0 Universal Login doesn’t happen. That being said if I refresh the page then the redirect to the Universal Login UI works.

Not exactly sure why the second redirect is followed and would be appreciative of any help.

Here’s the relevant code snippets. If anymore are needed let me know.

Protected Route Component

import { Navigate, useLocation } from 'react-router-dom';

interface ISession {
    userId: string;
    role: string;
    details: any;
}

type RouteProps = {
    children?: JSX.Element;
    session: ISession;
    loading: boolean;
};

const ProtectedRoute = ({ session, children, loading }: RouteProps) => {
  const location = useLocation();

    if (loading) return null;
    else if (!!session.userId) {
    return <Navigate to={location.pathname} state={{ redirectTo: location }} />;
  }
    else {
    return <Navigate replace to="/api/login" state={{ redirectTo: location.pathname }} />;
  }
};

export default ProtectedRoute;

The Login Handler on the Express API

const login = (req: Request, res: Response) => {
  const { redirectTo } = req.query;
  const domain = config.get('auth0.domain');
  const clientId = config.get('auth0.clientId');
  const host = config.get('host');

  if (redirectTo) {
    const encodedRedirect = base64.urlEncode(redirectTo as string); // A Custom Base64 encoder that is URL Safe
    res.status(301).redirect(`${domain}/auth/authorize?response_type=code&scope=openid&client_id=${clientId}&redirect_uri=${host}/api/auth/callback&state=${encodedRedirect}`)
  } else {
    res.status(301).redirect(`${domain}/auth/authorize?response_type=code&scope=openid&client_id=${clientId}&redirect_uri=${host}/api/auth/callback`);
  }
};



Solution

It’s not really an answer for what is going on but it is a solution.

The problem was <Navigate to="/api/login" /> would cause React to Rerender the page and would change the URL in the address bar, but it would not cause the browser to make a GET request to the new address.

To solve this I just overwrote the window.location.href with /api/login in the ProtectedRoute component.

Here’s the new version of the ProtectedRoute component.

const ProtectedRoute = ({ session, children, loading }: RouteProps) => {
  const location = useLocation();

  if (loading)
    return null;

  if (!!session.userId) {
    return children ? children : <Outlet />;
  }
  else {
    window.location.href = '/api/login';
    return <Navigate replace={true} to='/api/login' />
  }
};


This Question was asked in StackOverflow by HopAlongPolly and Answered by HopAlongPolly It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?