How to create private router using React Router v6.18.0 and the logic

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

https://medium.com/@tapan_sharma/private-routes-in-react-with-react-router-dom-v6-the-easy-way-1b95f68b8019

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

Leave a Reply

(*) Required, Your email will not be published