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 aslocalStorage
orsessionStorage
do not provide sufficient isolation against e.g. XSS attacks and the secrets kept inlocalStorage
can 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
localStorage
can 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
routesForNotAuthenticatedOnly
is excluded from the route configuration. Therefore, only the routes fromroutesForPublic
androutesForAuthenticatedOnly
will 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
routesForNotAuthenticatedOnly
routes 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
routesForNotAuthenticatedOnly
will 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
useContext
withuseReducer
can offer better maintainability for handling state changes.In my projects, I often utilize the combination of
useContext
anduseReducer
for 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
AuthProvider
component that implements the reducer pattern:And here is the updated version of the
Logout
component that utilizes theclearToken
function from theuseAuth
hook:Again thank you for sharing your thoughts. I appreciate your support!
this guy using A.I to reply lmao
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
Effector
orZustand
can 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 Toolkit
is 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:routesForNotAuthenticatedOnly
array will be included in the routes configuration.[]
will be included instead, effectively excluding theroutesForNotAuthenticatedOnly
from the routes configuration.(!token ? routesForNotAuthenticatedOnly : [])
.For the
routesForAuthenticatedOnly
, the logic is as follows:/
,/profile
, etc.), theProtectedRoute
component is responsible for checking if the user is authenticated./login
route using theNavigate
component fromreact-router-dom
.ProtectedRoute
component, 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 theroutesForAuthenticatedOnly
with the added protection of theProtectedRoute
component redirecting them to the login page if needed.Great Article.
Newly learned this function.
createBrowserRouter
Thanks for sharing what a great stuff easy to follow.
Great!
It described in good order and refined explanations.
Great Article
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?
same question
Your concern about relying solely on the existence of a token in localStorage for user authentication is valid. While it may not directly compromise security, it can affect the user experience. Here are two strategies to address this issue:
Implementing these measures not only ensures a smoother user experience but also strengthens the overall security of the authentication mechanism.
wow , awesome tutorial, straight to the point! just created an account here to give feedback :D
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.
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',
},
];
Nice article although, I face a problem.
I follow your steps, and when I login, I am navigated to the path "/" which is what I want, *but * the component/element is not showing up (it's a blank page). Only if I reload the page, it will come up. Why may that be?
very good template thanks a lot
Thanks Alot❤️ , Article is super simple to understand even I am beginner.
Exellent article
Very nice and detailed article. Simplified the concept for me.
Thank you so much man for this beautiful article with the simplest explanation.
Very helpful.
Great post!
Greate Article