skip to Main Content

This is my first question.
I am self-studying React.js, Node.js, and Express. For this reason, I am trying to create my own website where a user can register, log in, and access the page with their data only if the login is successful.

If the login is successful, a token is created using the user’s email as the payload. Additionally, I want to use a Higher Order Component (HOC)

Protect.js

import React, { useState, useEffect } from 'react';
import { Navigate } from 'react-router-dom';
import axios from 'axios';

const Protect = ({ component: Component }) => {
  const [authenticated, setAuthenticated] = useState(false);

  useEffect(() => {
    
    const checkAuth = async () => {
      try {
        
        const response = await axios.get('http://localhost:5000/checkAuth', { withCredentials: true });
        console.log('Protected GET Response:', response.data);
        
        if (response.status === 200) {
          setAuthenticated(true);
        } else {
          setAuthenticated(false);
        }
      } catch (error) {
        console.error('Protect: Error during auth', error.response);
        setAuthenticated(false);
      }
    };


    checkAuth();
  }, []);

return authenticated ? <Component /> : <Navigate to="/Login" />;

};

export default Protect;

so that in my App.js file, I have something like:

<Route
    path="/ProtectedPage"
    element={<Protect component={<ProtectedPage />} />}
/>

In the handleFormSubmit function of FormLogin, I added

      const handleFormSubmit = async (event) => {
    event.preventDefault();
  
    const formData = {
      email: email,
      password: password,
    };
  
    try {
      const response = await axios.post('http://localhost:5000/login', formData, { withCredentials: true });
      console.log("Client: Server Says: ", response.data);
      console.log("Client:  Login OK");
  
      navigate('/ProtectedPage');
    } catch (error) {
      console.log('Server Error:', error);
    }
  };

It might be useful to know that Protected makes a GET request to

const verifyToken = (req, res, next) => {
  const token = req.cookies.token;

  if (!token) {
    res.status(401).send('Access Denied');
  } else {
    jwt.verify(token, secret, function (err, decoded) {
      if (err) {
        res.status(401).send('No Valid Token!');
      } else {
        req.email = decoded.email;
        req.token = token;
        console.log('verifyToken: ', req.email);
        next();
      }
    });
  }
};

app.get('/checkAuth', verifyToken, (req, res) => {
    res.sendStatus(200).send({ authenticated: true, email: req.email, token: req.token});
});

You can view my code at this link: https://github.com/CiccioLagXCVIII/MyOwnSite.git

But even if the login is successful, I don’t get any errors or redirection to /ProtectedPage

Thanks to anyone who will respond.

I have already tried using console.log to verify if the data is received and sent correctly, and it is. My issue is that I don’t see any errors (I only see the logs that I have entered myself for debugging) in the console when the login is successful, but the redirection doesn’t happen.

2

Answers


  1. First just a clarification on nomenclature: Protect isn’t a Higher Order Component, e.g. it’s not a function that takes a React component as an argument and returns a decorated React component, it is just a regular React component that takes a component prop.

    The issue is that Protect uses an initial authenticated value that matches unauthenticated users and on the initial render will redirect users to the "/login" route.

    Start from an "unknown" authentication state and wait for the checkAuth code to complete and update the authenticated state prior to rendering the protected content or redirecting.

    Example:

    const Protect = ({ component: Component }) => {
      const [authenticated, setAuthenticated] = useState(); // <-- initially undefined
    
      useEffect(() => {
        const checkAuth = async () => {
          try {
            const response = await axios.get(
              'http://localhost:5000/checkAuth',
              { withCredentials: true }
            );
            setAuthenticated(response.status === 200);
          } catch (error) {
            setAuthenticated(false);
          }
        };
    
        checkAuth();
      }, []);
    
      if (authenticated === undefined) {
        return null; // <-- or loading indicator/spinner/etc
      }
    
      return authenticated ? <Component /> : <Navigate to="/Login" replace />;
    };
    
    Login or Signup to reply.
  2. i think you have imported useNavigate hook, if not must import. and if don’t work you can try this.

    import React from 'react';
    import { Navigate, useLocation } from "react-router-dom"
    import { useSelector } from 'react-redux';
    import { selectAuthState } from './redux/features/auth/authSlice';
    
    const PrivateRoute = ({ children }) => {
        const isAuthenticated = useSelector(selectAuthState);
        let location = useLocation();
    
        if (!isAuthenticated) {
            return <Navigate to="/login" state={{ from: location }} replace />
        }
    
        return children;
    };
    
    export default PrivateRoute;
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search