How to redirect to homepage after successful token validation


ProtectedRoute.js

import { Navigate } from 'react-router-dom';
import Cookies from 'js-cookie';
import { checkToken } from './auth';
import Admin from '../pages/Admin-page/Admin';

const ProtectedRoute = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [isValid, setIsValid] = useState(false);

  useEffect(() => {
    const verifyToken = async () => {
      try {
        const valid = await checkToken(); 
        console.log('Token valid:', valid); // Debugging

        setIsValid(valid);
      } catch (error) {
        console.error('Error validating token:', error);
        setIsValid(false);
      } finally {
        setIsLoading(false);
      }
    };

    verifyToken();
  }, []);

  if (isLoading) {
    return <div>Loading...</div>; 
  }
  console.log('Token isvalid:', isValid); // Debugging

  return isValid ? <Admin /> : <Navigate to="/login" replace />;
};

export default ProtectedRoute;

App.js

import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Login from './authentications/Login';
import Users from './pages/Side-menu/Users';
import Hours from './pages/Side-menu/Hours';
import Tenants from './pages/Side-menu/Tenants';
import ResetPassword from './authentications/ResetPassword';
import NewPassword from './authentications/NewPassword';
import ProtectedRoute from './authentications/ProtectedRoute';
import PostContent from './pages/Admin-page/PostContent';
import Admin from './pages/Admin-page/Admin';
import Home from './pages/Side-menu/Home';
import Signup from './authentications/Signup';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/login" element={<Login />} />
        <Route path="/signup" element={<Signup />} />
        <Route path="/forgotpassword" element={<ResetPassword />} />
        <Route path="/newpassword" element={<NewPassword />} />

        {/* Protected routes */}
        <Route
          path="/"
          element={
            <ProtectedRoute>
              <Admin />
            </ProtectedRoute>
          }
        >
          <Route path="admin/posts" element={<PostContent />} />
          <Route path="admin/users" element={<Users />} />
          <Route path="admin/hours" element={<Hours />} />
          <Route path="admin/tenants" element={<Tenants />} />
        </Route>
      </Routes>
    </Router>
  );
}

export default App;

Login.js

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useTranslate } from '@tolgee/react';
import { LanguageSelect } from '../LanguageSelect';
import { checkToken } from './auth'; 
import axios from 'axios'; 
import Cookies from 'js-cookie'; 

function Login() {
  const [formData, setFormData] = useState({
    email: '',
    password: '',
  });
  const [errors, setErrors] = useState({ password: '' });
  const navigate = useNavigate(); // Přidání useNavigate hooku
  const { t } = useTranslate();

  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData({ ...formData, [name]: value });
  };

  const validatePassword = (password) => {
    const regex = /^(?=.*[A-Z])(?=.*\d)[A-Za-z\d@#$%^&+=!]{8,}$/; // Updated regex
    return regex.test(password);
  };

  const handleLogin = async (e) => {
    e.preventDefault();

    if (!validatePassword(formData.password)) {
      setErrors({
        password:
          'Password must be at least 8 characters long, contain at least one uppercase letter and one number.',
      });
      return;
    }

    try {
      const response = await axios.post(
        'https://MYWEBSITE/api/v1/users/login',
        {
          email: formData.email,
          password: formData.password,
        },
        {
          headers: {
            'Content-Type': 'application/json',
          },
          withCredentials: true, // Added withCredentials setting
        }
      );

      if (response.status === 200) {
        console.log('Login successful.');
        setFormData({
          email: '',
          password: '',
        });
       
    
       
        const isValidToken = await checkToken();
        if (isValidToken) {
          console.log('Token is valid, navigating to homepage.');
    

          navigate('/'); // Redirect after successful login
        } else {
          console.error('Invalid token after login.');
        }
      } else {
        console.error('Error logging in:', response.statusText);
      }
    } catch (error) {
      console.error('Axios error:', error);
    }
  };

 
export default Login;


auth.js:

import axios from 'axios';

export const checkToken = async () => {
  try {
    const response = await axios.get(
      'https://MYWEBSITE/api/v1/users/checkToken',
      {
        headers: {
          'Content-Type': 'application/json',
        },
        withCredentials: true, 
      }
    );

   
    return response.data.status === 'success';
  } catch (error) {
   
    if (error.response) {
    
      console.error('Server error:', error.response.data);
      return false;
    } else if (error.request) {
   
      console.error('Network error:', error.request);
      return false;
    } else {
  
      console.error('Request error:', error.message);
      return false;
    }
  }
};

I use protected routes in ReactJS and it correctly checks the validity of the token, but it still redirects me back to Login and not to the homepage, which is Admin.js. I tried use <Outlet/> in my Protected Route, but it didn't work. In the console I check if the token is validated correctly and I have no problem there. I've been sitting on this for a long time and haven't found a solution on any platform. It's possible that I have a bug somewhere in App.js, because I'm working with Protected Route for the first time and I don't know if I've written it correctly.

Upvotes: 0

Views: 39

Answers (1)

A-L
A-L

Reputation: 21

you can work with passport.js: server :

import express from 'express';
import passport from 'passport';
import jwt from 'jsonwebtoken';
import dotenv from 'dotenv';

dotenv.config();

const router = express.Router();
const { CLIENT_URL } = process.env;

// Initial route to start the authentication process
router.get('/google',
  passport.authenticate('google', { scope: ['profile', 'email', 'openid'] })
);

// Callback route that Google redirects to after authentication
router.get('/google/callback', 
  passport.authenticate('google', { failureRedirect: '/login', session: false }),
  (req, res) => {
    if (!req.user) {
      return res.redirect('/login');
    }

    // Create JWT token
    const token = jwt.sign({ userId: req.user.googleId }, process.env.JWT_SECRET, { expiresIn: '1h' });

    // Set token as HTTP-only cookie
    res.cookie('token', token, { httpOnly: true });

    // Create a user profile object
    const userProfile = {
      googleId: req.user.googleId,
      displayName: req.user.name,
      email: req.user.email,
      picture: req.user.picture,
    };

    // Redirect to client with user profile in URL
    // res.redirect(`${CLIENT_URL}/?profile=${encodeURIComponent(JSON.stringify(userProfile))}`);
    res.redirect(`${CLIENT_URL}/messenger?profile=${encodeURIComponent(JSON.stringify(userProfile))}`);

  }
);

export default router;

client:

import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import AccountProvider from './context/AccountProvider'; 

//components:
import Messenger from './components/Messenger';

export const App = () => {
  
  return (
    <Router>
      <AccountProvider>
        <Routes>
          <Route path="/" element={<Messenger />} />
          <Route path="/messenger" element={<Messenger />} />
        </Routes>
      </AccountProvider>
    </Router>
  );
};

export default App;

Upvotes: 0

Related Questions