In this blog post, we'll explore the seamless integration of JWT authentication with React and react-router. We'll also learn how to handle public ...
For further actions, you may consider blocking this person and/or reporting abuse
Please keep in mind the implications of storing secrets such as access tokens (e.g. a JWT) in
localStorage. Browser storage such aslocalStorageorsessionStoragedo not provide sufficient isolation against e.g. XSS attacks and the secrets kept inlocalStoragecan easily be exposed by malicious code.Further reading:
auth0.com/blog/secure-browser-stor...
snyk.io/blog/is-localstorage-safe-...
Thank you for raising this important concern. You're absolutely right that storing access tokens or any sensitive information in
localStoragecan pose security risks, especially in the context of XSS attacks. It's crucial to consider these implications and take necessary precautions.One alternative approach to mitigate such risks is to use techniques like HttpOnly cookies or secure authentication mechanisms. By employing secure storage methods and implementing best practices, we can enhance the overall security of our applications.
I appreciate your valuable input and the reminder to prioritize security in handling sensitive data.
Exellent article, well described and organized, easy to follow.
I didn't understand something on the router. It defines two "/" routes to main, but how it know which one use?
I didn't catch how the router detects when to use the public and the authorized one.
Thank you for your kind words! I'm glad you found the article helpful.
In React Router, the routes are processed in the order they are declared. This means that the first matching route will be rendered.
When a user navigates to a specific route, React Router will check the routes in the order they are defined. If a route's path matches the current URL, React Router will render the corresponding element.
When the user is authenticated (has a token), the
routesForNotAuthenticatedOnlyis excluded from the route configuration. Therefore, only the routes fromroutesForPublicandroutesForAuthenticatedOnlywill be considered. If the path matches "/", React Router will render the<ProtectedRoute />component, which leads to the "User Home Page" component being displayed.On the other hand, when the user is not authenticated (no token), the
routesForNotAuthenticatedOnlyroutes are included. In this case, if the path matches "/", React Router will render the "Home Page" component fromroutesForNotAuthenticatedOnly, because it is declared before the routes fromroutesForAuthenticatedOnly.The order of route declaration is significant. React Router processes the routes in the order they are defined, and the first matching route is rendered. In this scenario, since the path "/" matches the first route in
routesForNotAuthenticatedOnly, that route's corresponding component will be rendered.So, to clarify, when the user is not authenticated, the "Home Page" component from
routesForNotAuthenticatedOnlywill be rendered when the path matches "/", as it is declared before the routes fromroutesForAuthenticatedOnly.By conditionally including different route configurations based on the authentication status, you can control which routes are available to the user and which components are rendered for different scenarios.
That was a Mega explanation!
All clear, thanks!
Hi, very good article, but I think it is more maintainable if we use useContext with useReducer for these cases, in this way we handle possible predefined state changes and we don't let them change in any way through the code. this way we can have a useAuthStateContext and a useAuthDispatchContext to make it more maintainable and even easier to use. greetings and congratulations!
Thank you for your feedback and congratulations! I appreciate your input and agree that using
useContextwithuseReducercan offer better maintainability for handling state changes.In my projects, I often utilize the combination of
useContextanduseReducerfor managing authentication state. However,for the purpose of this article, I have chosen to simplify the implementation and use
useState.Here is the updated version of the
AuthProvidercomponent that implements the reducer pattern:And here is the updated version of the
Logoutcomponent that utilizes theclearTokenfunction from theuseAuthhook:Again thank you for sharing your thoughts. I appreciate your support!
Good stuff Sanjay, thanks for sharing,
just a little clarification about file name:
authProvider.js is really authProvider.jsx
if you use .js you will get the following/similar error:
Of course you have the right file name in the source code. :-)
Good post, thank you 🙏
What do you think instead of using Context API, using Effector or Zustand?
What if backend sends you an HTTP cookie (JWT), that JWT includes time of creation and time expiration. This is jus first part of the full token, with the second part stored on the server. You only need to check expiration time of the token.
Thank you for your kind words! When it comes to alternative state management solutions, libraries like
EffectororZustandcan offer different approaches compared to the Context API. While I haven't personally worked with Effector and Zustand, I do plan on exploring them in the future. However, I can share thatRedux Toolkitis a widely adopted and powerful state management solution that I intend to cover in an upcoming article.Regarding JWT tokens with time of creation and expiration, it is a common practice in authentication. If the backend sends the JWT as an HTTP cookie, you can extract relevant information such as the expiration time from the token and store it on the client-side. By checking the expiration time, you can determine the token's validity. If the token has expired, you may need to handle token renewal or reauthentication based on your application's requirements.
Hi,
Why do we need to create ? Why not simply do the following:
const router = createBrowserRouter([
...routesForPublic,
...(!token ? routesForNotAuthenticatedOnly : []),
...(token ? routesForAuthenticatedOnly : [] ),
]);
We check the token here in createBrowerRouter itself. This is easier and much more maintainable.
For the
routesForNotAuthenticatedOnly, the logic is as follows:routesForNotAuthenticatedOnlyarray will be included in the routes configuration.[]will be included instead, effectively excluding theroutesForNotAuthenticatedOnlyfrom the routes configuration.(!token ? routesForNotAuthenticatedOnly : []).For the
routesForAuthenticatedOnly, the logic is as follows:/,/profile, etc.), theProtectedRoutecomponent is responsible for checking if the user is authenticated./loginroute using theNavigatecomponent fromreact-router-dom.ProtectedRoutecomponent, where it checks if the user is authenticated and handles the redirection accordingly.Overall, these mechanisms ensure that the appropriate routes are accessible based on the user's authentication status. If the user is not authenticated, they can access the
routesForNotAuthenticatedOnly, and if they are authenticated, they can access theroutesForAuthenticatedOnlywith the added protection of theProtectedRoutecomponent redirecting them to the login page if needed.Great Article.
Newly learned this function.
createBrowserRouterGreat Article
Thanks for sharing what a great stuff easy to follow.
Great!
It described in good order and refined explanations.
Wish I could send this to every programmer that had the same struggles that I did, not only did you gave a perfect explanation on handling the token but also routes.
Great job and thank you.
This article was amazing. I'm using the createBrowserRoutesFromElements function, but it seems I'll change that.
A question I have for you is, how would someone handle refresh tokens using this setup? Thanks
But if we decide whether user is authenticated or not, just on the basis of existence of token, is it okay? won't if user manually add some garbage into the localStorage via inspecting, will let him sign in?
Is there any solution for this?
one solution I think, we can verify the validity of jwt in frontend, ig?
If I change
const routesForNotAuthenticatedOnly = [
{
path: "/",
element:,
},
];
to that,this exception occurs "Objects are not valid as a React child (found: [object RegExp]). If you meant to render a collection of children, use an array instead."
You need to provide the element you want to render when a path is visited.
const routesForNotAuthenticatedOnly = [{
path: "/",
element: 'NEED_TO_PROVIDE_COMPONENT_HERE',
},
];
While the article features JWT in the title (a clickbait apparently), there is no JTW in the content or github example, besides
setToken("this is a test token");how can i handle nested route.
currently at / i have component
and inside i have structure of login page like in Login compo i divided page in two half one half has image and in second half based on route i render either login or sign up . so fo that i have two route set up . at / i have and at at /sign-in i have
with your auth set up this is not working.
Exellent article
Thanks Alot❤️ , Article is super simple to understand even I am beginner.
very good template thanks a lot
Thank you so much man for this beautiful article with the simplest explanation.
Very helpful.
Very nice and detailed article. Simplified the concept for me.