Protected routes allow us to ensure only logged in users can access certain parts of our site that may contain private user information. In this ...
For further actions, you may consider blocking this person and/or reporting abuse
Not work if i refresh '/dashboard'
@juanortizoviedo - I had the exact same problem so once the web browser is refreshed whilst the URL is
/dashboard
, the page is automatically redirected to/unauthorized
which makes sense as this is specified inProtectedRoute
.I tried refreshing the browser whilst on
/unauthorized
page and it worked as expected (reloaded/unauthorized
as normal).I've since created a fresh create-react-app project with firebase and authenticating a user with either email or google provider and this exact same refresh issue is happening. It's almost as if the user is authenticated quickly enough on page load so the browser redirects the specified page or back to the root (
/
) URL.So if a user (authenticated or not authenticated) refreshes the browser on a non-protected page, everything is fine but they are redirected if already on a protected page.
Have you managed to figure out how to overcome this issue? Any help would be greatly appreciated @mychal
Have a read over the answer here: stackoverflow.com/questions/279283...
Client side routing is hard! Basically what you're seeing is the server try to find something at /route, when your SPA loads from /index.html - /route doesn't 'really' exist - until your index.html is read and your JS kicks in. It really blows your mind until you get it. Using react router you can evade this issue by using hashrouting
@franciscobenedict I had this exact same issue. Firebase will persist an authenticated users details in local storage, however to retrieve them initially is asynchronous which as you've experienced doesn't work when refreshing the page and you get taken to a login screen, etc.
As we will be wanting to know about this user state across multiple components its advised to wrap all this logic into a context provider. To start solving this we can utilise
onAuthStateChanged
from Firebase which is the recommend way of retrieving a user as it allows Firebase to initialise, it will provide either the user object ornull
in the callback. What we also need is a loading state, which is true on initial launch and when the user has been loaded or if there isn't one we can stop loading. To get this behaviour we can wraponAuthStateChanged
in a promise which resolves the user and call it on initial launch usinguseEffect
. We can then wait for this promise to settle before we manage our final loading state. Finally we can decide what to do once we've finished loading and we either have or don't have a user.Here's my code:
Helper function
AuthContext.js
ProtectedRoute.js
The issue seems to be as simple as the demo application doesn't have a persisting state of the user's auth. Since it's just artificially creating auth for a user and storing it in memory. The state of the user being logged in can't survive a page refresh. So naturally when you login and going to dashboard via the on page links it works but when you do a page refresh the user's current logged in state is lost from memory and defaults back to its original state of false. Look at the React Developer Tools and monitor the components state regarding the user's auth. A solution to this in a real application would be to have some state management system like context or Redux to persist the state so the accurate page shows when expected.
I came across this issue when working with protected routes. The reason as you've already figured out, is due to the user state initially being sent to our components (defaults as false), so when it hits our protected route, it redirects the user to 401 unauthorised. What I did to solve this issue was check the user state before returning the routes. To "load" the app before it actually hit the router. I've attached some sample code, hopefully helps someone stuck with this.
gist.github.com/FaizanH/88ede257df...
There must be a typo
What a wonderful guide!
There were a couple things that caught me while following along:
Thank you so much for this article though! It was very helpful for me!
Unfortunately when I try this approach and hit the protected route, I get a show-stopping error: 'Invariant failed: You should not use <Route> outside a <Router>'. Seems like it doesn't like me composing something around the Route component, but I don't know why you and I get different results for that.
Thank you :-)
No problem, thanks for reading!
great article
i have tried to do the same thing in my application but i have a problem
the data that i passed to the ProtectedRoutes are undefined i don't know why
at first the date are present but once i click on the login button which must change the Auth state to true after an API call.
but once i receive the data they are lost in the ProtectedRoute and are set to undefined
Thanks for sharing your knowledge. I don't understand why implementing this idea in my other project took me a long time. You made it so simple to protect private routes in ReactJS. Thanks again.
Anyway to implement this with page refresh?
Thank you , it was very helpful
Very useful, thank you very much!
This is really good guide. I quite enjoyed it. Very easy to follow and concise too. Well done @mychal
great job.... thanks
This is a highly understandable guide. Kudos to you sir
Thanks for the knowledge!
what if someone just add /dashboard in url? Thats the problem i have to deal with. Any solution to it?
After so many days of struggle finally i found it
Thank you for the detailed breakdown of Protected Routing Mychal!
Thanks! I was struggling with other tutorials to understand the HOC that abstract the logic of protecting the components but now I understand thanks to you.