Issue
I can’t find the logic and how to create private routes with react-router v6.18.0.
import * as React from "react";
import {createRoot} from "react-dom/client";
import {
createBrowserRouter,
RouterProvider
} from "react-router-dom";
import Home from "./views/Home";
import Register from "./views/Register";
import Login from "./views/Login";
import 'bootstrap/dist/css/bootstrap.min.css';
import Dashboard from "./views/Dashboard";
const router = createBrowserRouter([
{
path: "/",
element: <Home/>,
}, {
path: "/login",
element: <Login/>,
}, {
path: "/register",
element: <Register/>,
}, {
path: "/dashboard",
element: <Dashboard/>,
}
]);
createRoot(document.getElementById("root") as HTMLElement).render(
<RouterProvider router={router}/>
);
So I’d like my "/dashboard" to be private.
On the back-end, I’m using Node.js, TypeScript, Express and PostgreSQL.
For authentication, I use jsonwebtoken. When I authenticate with a user, I send my generated token in my header, for example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c".
I have read that the way to do this is to store the token in the localStorage. So I had the idea to store my token in my localStorage and before each route to check if my localStorage has the token. But I don’t think it’s secure, because if I create a token and store it with the same name using my browser console. I’d still be able to access my Dashboard.
So I don’t see how to do it at all.
Here’s my backend login route:
app.post("/login", async (req, res) => {
const findUserByEmail = await userRepository.findByEmail(req.body.email)
if (!findUserByEmail) {
res.status(404).send("User not found.")
} else {
const passwordResult = await passwordService.comparePasswords(req.body.password, findUserByEmail.password)
if (!passwordResult) {
res.status(409).send("Wrong password.")
} else {
const token = await jwtService.jwtSign({
id: findUserByEmail.id,
fullName: findUserByEmail.firstName + "" + findUserByEmail.lastName,
email: findUserByEmail.email
})
res.setHeader('Authorization', 'Bearer ' + token);
res.status(200).send("Logged in.")
}
}
})
Can you help me? Thanks
Solution
if you want to create private route in react router v6
you can use httponly cookie if you dont want to store jwt in browser. httponly cookie cannot be modified by browser
in node js you send cookie to browser like this
res.cookie('jwt', token, {
expires: new Date(
Date.now() + process.env.JWT_COOKIE_EXPIRES_IN * 24 * 60 * 60 * 1000
),
httpOnly: true,
secure: req.secure || req.headers['x-forwarded-proto'] === 'https',
sameSite: process.env.NODE_ENV === 'development' ? 'strict' : 'none',
});
in front end, if you are using fetch for api calls you have to pass credentials option to send cookie along with request
const requestOptions = {
method: 'GET',
credentials: 'include',
};
if you are using axios ,you have to pass this option
withCredentials: true
in nodejs to access the jwt token:
req.cookies.jwt
To check if user is logged in or not, make a get api to return if user is logged or not or not like /isLoggedIn and save the response in state for condition in private route
Answered By – Sajan Dhakal
This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0