I am generating an accessToken for a user upon Login and a refreshToken
which helps to regenerate another accessToken for the user
if the user trys to refresh a page or the token times out.
but the problem is though these tokens are generated as it should be,
I am always redirected to Login page when I refresh the page
or when I click to access another Tab in the menue. What could
be the problem here.
//here is the Routes
const App = () => {
return (
<Routes>
<Route path='registerPage' element={<RegisterPage />} />
<Route path='logIn' element={<LogInPage />} />
{/* Protected Routes */}
<Route element={<PersistLogIn/>}>
<Route element={<RequireAuth />}>
<Route path='/' element={<Layout />}>
<Route index element={<Home />} />
<Route path='dashboard' element={<HomeLayOutt />} />
<Route path='moneyIn' element={<MoneyIn />} />
<Route path='moneyOut' element={<MoneyOut />} />
<Route path='inventory' element={<Inventory />} />
</Route>
</Route>
</Routes>
//LogIn Page
const LogInPage = () => {
const [username, setUserName] = useState("")
const [password, setPassWord] = useState("")
const {setAuth} = useAuth()
const handleUser_Name =(e)=>{
setUserName(e.target.value)
}
const handlePass_word = (e)=>{
setPassWord(e.target.value)
}
const location = useLocation()
const from = location.state?.from?.pathname || '/'
const navigate = useNavigate()
const goToRegister =()=>navigate('/registerPage')
const handleLogIn=()=>{
Axios.post('http://localhost:3500/auth', JSON.stringify({username, password}),
{
headers:{'Content-Type' : 'application/json'},
withCredentials: true
}
)
.then(res=> {
console.log(JSON.stringify(res?.data))
console.log((res?.data))
const accessToken = res?.data?.accessToken
setAuth({username, password, accessToken})
setUserName('')
setPassWord('')
navigate(from, {replace: true})
}).catch(err =>{console.log(err)})
}
}
//Context API(AuthProvider)
import { createContext, useState } from "react";
const AuthContext = createContext({})
export const AuthProvider =({children})=>{
const [auth, setAuth] = useState({})
console.log(auth)
return(
<AuthContext.Provider value={{auth, setAuth}}>
{children}
</AuthContext.Provider>
)
}
export default AuthContext
//useAuth
import { useContext } from "react";
import AuthContext from "../context/AuthProvider";
const useAuth = () =>{
return useContext(AuthContext)
}
export default useAuth
//RequireAuth
import {useLocation, Navigate, Outlet} from 'react-router-dom'
import useAuth from '../hooks/useAuth'
//check if the user is logged in or not
//this is a component that will help us protect our routes
const RequireAuth = () =>{
const {auth} = useAuth()
const location = useLocation()
console.log(auth)
return(
auth?.username ? <Outlet/> : <Navigate to='/login' state={{from: location}} replace/>
)
}
export default RequireAuth
//PersistLogIn
const PersistLogIn = () => {
const [isLoading, setIsLoading] = useState(true)
const refresh = useRefreshToken()
const {auth, persist} = useAuth()
useEffect(()=>{
const refreshTokenVerify = async () =>{
try{
await refresh()
}
catch(err){
console.error(err)
}
finally{
setIsLoading(false)
}
}
!auth?.accessToken ? refreshTokenVerify() : setIsLoading(false)
},[])
useEffect(()=>{
console.log(`isLoading: ${isLoading}`)
console.log(`aTh: ${JSON.stringify(auth?.accessToken)}`)
},[isLoading])
return (
<>
{isLoading
? <p>Loading...</p>
: <Outlet />
}
</>
)
}
export default PersistLogIn
//BackEnd
//authController
const handleUserLogIn = async (req, res)=>{
const {username, password} = req.body
if(!username || !password) return res.status(400).json({'message':'username or password is required'})//Bad Request
const foundUserData = await User.findOne({username}).exec();
console.log(foundUserData)
if(!foundUserData) return res.sendStatus(401)//Unauthorized
const validPassword = await bcrypt.compare(password, foundUserData.password)
if(!validPassword){
return res.sendStatus(401)//Unauthorized
}else{
//create the JWT
const accessToken= jwt.sign({'username':foundUserData.username},
process.env.ACCESS_TOKEN_SECRET, {expiresIn: '30s'})
const refreshToken= jwt.sign({'username':foundUserData.username},
process.env.REFERESH_TOKEN_SECRET, {expiresIn: '5m'})
//save refreshToken with current user
foundUserData.refreshToken = refreshToken
const result = await foundUserData.save()
console.log(result)
//create a secured cookie with refreshToken
res.cookie('jwtToken',refreshToken, {httpOnly: true, maxAge: 300000} ) //secure: true
//res.cookie('token', accessToken, {httpOnly: true, maxAge: 20000})
//Send access Token to user
res.json({accessToken})
}
}
module.exports={handleUserLogIn}
//refreshTokenController
const handleRefreshToken = async(req, res)=>{
const cookies = req.cookies
console.log(cookies.jwtToken)
if(!cookies?.jwtToken) return res.sendStatus(401)//unauthorized //.jwt
console.log(cookies.jwtToken)
const refreshToken = cookies.jwtToken
const foundUserData2 = await User.findOne({refreshToken}).exec()
if(!foundUserData2) return res.sendStatus(403)//Forbidden
//evaluate JWT
jwt.verify(refreshToken, process.env.REFERESH_TOKEN_SECRET,
(err, decoded)=>{
if(err || foundUserData2.username !== decoded.username)return res.sendStatus(403);//forbidden
//another accessToken is created
const accessToken = jwt.sign(
{'username':decoded.username},
process.env.ACCESS_TOKEN_SECRET,
{expiresIn: '30s'}
)
res.json({accessToken})
})
}
module.exports = {handleRefreshToken}