Protected routes and authentication with React Router v4
Articles Blog

Protected routes and authentication with React Router v4

February 28, 2020

In this video, we are going to learn about
protected routes and authentication with React Router by going through this Redirects example
on the React Router documentation. So let’s go ahead and take a look at the final
app that we’re going to be building. You’ll notice here that the default page,
we get a few different options. We have you are not logged in, and then we
have two links. This Public Page is a page that anyone can
see. You don’t need to be authenticated to see
it. But when we click on the Protected Page, you’ll
notice what happens is it says, “Hey, you must be logged in to view the page at /protected.” And we got redirected to the login page. So if we go ahead and click on Log in, then
you’ll notice that we get taken back to the Protected Page where we can now navigate around
and we can see all the different links in the app. And then when we are done, we can go ahead
and sign out, which will then take us back to the index page. So as always, the very first thing we are
going to do is import some components from React Router. So we will get BrowserRouter and we will name
it Router. Then we will get Route, Link, and a Redirect
component. And all of those are going to be coming from
react-router-dom. All right, so the very first thing we’re going
to do is just create a little bit of a fake authentication kind of service. So what we’ll do here is we will say fakeAuth,
which is just going to be an object which has an isAuthenticated property on it, which
is going to be set to false and then it will have two different methods. We will just say authenticate, which takes
in a callback function, is going to change isAuthenticated to true. And after a slight delay, we’re going to go
ahead and call the callback. So basically what we’re doing here is we just
have some fake asyncs so we can, kind of, pretend like we’re actually authenticating. And then the last one we have is just called
signout. This basically is going to do the exact same
thing. It’s going to change isAuthenticated to false. And then after a slight delay, it’s going
to call the callback that was passed in. So again, the only reason we have this is
so we can actually fake like we’re doing real authentication inside of our application. Now what we’re going to do is let’s go ahead
and build a few different components that are going to be rendered when we get two different
routes in our application. So the first one we will call it Public, and
all it’s going to do is render an

element. We’ll say Public. The next one is going to be very similar,
so I’m just going to copy and paste. Instead of Public, we’re going to say that
this one is Protected. So what we’re going to do is we’re only going
to show this component when the user is authenticated, and if not, we’re going to redirect them to
the login page. And then what we’ll do is we will build a
class called Login, which extends React.Component. And for now, all we’re going to do is have
a render method that is going to return us a

, and then we will just say LOGIN. All right, so now that we have kind of the
skeletons of this example built, let’s actually go ahead and update our actual app. So what we’ll do, as always, is we will render
a Router. And then inside of that, we are going to have

. And then inside of here, we are going to have
an unordered list, which is going to act as our navigation. In this example, we are going to have two
different list items which means we’re going to have two different links. So let me go ahead and build both of those. Both will have a to prop. And the first one is going to take us to the
Public Page, and the second one is going to take us to a Protected Page. The very first to prop we’ll say to /public,
and the second one we will say to /protected. All right, so if we render this, what we should
see if we don’t have any errors is just two links. And then now, as we’ve done before, we want
to go ahead and render some routes. So the very first one, we will go ahead and
say when we are on /public, the component that we want to render is the Public component
that we built earlier. I’m going to copy and paste this because we’re
going to do something similar for our login path as well. So now what we should see here is we have
the Public Page. We have the Protected Page, which is not a
thing right now. And then we also have this login page, which
just shows us LOGIN. So now what we want to do is we actually want
to create a private route so that we can actually render something when we go to the Protected
Page, but only if the user is actually authenticated. So it would be nice if we could do something
like this. Like, if React Router came with a built-in
PrivateRoute component, and then we can use it kind of the same as we would a normal route. So we would say protected, and then the component
we want to render is just the Protected component. The problem is React Router doesn’t come with
a PrivateRoute component because really we can just build our own PrivateRoute component
using a normal route. So what that would look like is let’s go up
here, and we will create a brand new component and we’ll call it PirvateRoute. And what it’s going to take in is, as we see
here, a path as well as a component. So we’re going to go ahead and destructure
this so that we can rename the Component to use a capital C because it’s a component. And then we’ll go ahead and grab the rest
of the arguments, or in this case, the rest of the props past the component. And then now, what we want to render is just
a route because we have a protected route. So it really is just going to be a route under
the hood. We’re going to go ahead and spread all of
those rest props onto our Component. And then we’re going to use React Router’s
render prop to say whenever the path matches this path or whatever path was passed to the
private route, go ahead and render this function. So now the question is what are we going to
render when the path matches? Well, now what we can do is, if you’ll remember,
we have our fakeAuth object up here. So we can come in here and we could say if
fakeAuth.isAuthenticated, so if that’s true, then what we want to do is just render the
component as normal passing in all of the props that we’re going to get from render. So these props are going to be the normal
props that are passed to a component that’s rendered by React Router. Specifically, they’re going to be location,
match, and the last one is history. So those three props, we’re just going to
go ahead and pass those to the component as normal. But if we’re not authenticated, then we want
to go ahead and redirect the user to the login page so that they can obviously log in. So that’s where React Router’s Redirect component
is going to come into play. So we’re going to render a Redirect, and we’re
going to say go ahead and take the user to /login. So now what should happen if we don’t have
any errors… So we’re on the Public Page, and when we go
to the Protected Page, you’ll notice that we are routed to our login route, which then
renders the login component so that the user can log in. So everything seems to be working so far. Let’s go ahead and test this. Instead of having isAuthenticated be set to
false by default, let’s go ahead and set it to true. And then now when we go to the Protected Page,
you’ll notice that we get our Protected component here, which is right here, being rendered. Again, let me walk you through the flow of
that just real quick. So what we do inside of our app, we render
a few normal routes. And then we render this PrivateRoute passing
it a path, just as we normally would, as well as a component. Then we render a route because our PrivateRoute
really is just a route. We spread all of the arguments that were passed
to the component onto that route. We have a render method. So this is going to be invoked when the path
matches. And then if we’re authenticated, we render
the component just as we normally would. And if we’re not, we go ahead and redirect
to login. So now what we need to do is we need to fix
our login component, or add more to it, so that we can actually log in rather than just
toggling this isAuthenticated property by hand. So what we’ll do is inside of our Login component,
let’s add some state here. And we’re going to go ahead and add a property. We’ll call it redirectToReferrer, and that’s
just going to be defaulted to false. And then what we’ll do is let’s go ahead and
add a method onto here called login. And what this is going to do is it’s going
to call fakeAuth.authenticate. We’re going to pass it a callback function. And when this callback function is invoked,
we will call setState, and then we’re going to change redirectToReferrer to true. So what this is going to allow us to do is,
now inside of our render method, we’re aware or we know when we need to redirect. So then what we can do is we can come down
here and say… Let’s just go ahead and grab this off of our
state. And then we can say if redirectToReferrer
equals true, then let’s go ahead and, just as we did before, render a Redirect. And where are we going to go? We’re going to go to the index page. Then what we want to do is if redirectToReferrer
does not equal true, then we will see this UI right here. Let’s go ahead and render a paragraph and
we just will say, “You must log in to view this page.” And then we will render a button that when
it is clicked on will call our login method that we made up here. And we’ll just say Log in. All right, so now if this is working, what
should happen is… Let’s go ahead and go to the Public Page. Now when we try to go to the Protected Page,
we get taken to our login page. Now when we click on Log in, notice that we
get redirected back to the Public Page, and now we can see our Protected Page. So it’s pretty cool. It’s working and we have now this protected
route that only lets us view it if the user is authenticated. Let’s go ahead and add a little bit more functionality
to our app right now. I’m going to refresh this. So you’ll notice that when I click on Protected
Page, I get redirected to login. And then when I click on Log in, I get redirected
back to the Public Page. I think it’s a better experience if instead
of trying to get to the Protected Page, logging in and then getting taken back to the Public
Page, it would make more sense if we saved what pages the user was trying to go to, in
this case, the Protected Page, and then once they authenticate, take them back to the original
page that they wanted to go to rather than just taking them back to the index page. So in order to do that, what we’ll do is inside
of our protected route component down here, when we redirect to our login page, we actually
want to pass along the current page the user is trying to go to, so that way once we log
in, we can redirect back to that page. So what we’ll do is instead of passing redirect,
or instead of passing this to prop a string, what we can do is we can pass it an object
with the pathname set to login. So we’ll take them to the login page. But we’re also going to pass along some state. And we’re going to say the user is coming
from props.location because props.location, again, is the route that the user is trying
to get to when this private route is rendered. So then what that allows us to do is, if we
go back to our Login component now, this Login component is going to be passed some props. So what we’ll do is we will come up here and
say from. And this is going to be the this.props.location.state. Or if that’s not a thing, then we’ll go ahead
and just set that equal to something like this. So what this is doing is it’s saying if we
got redirected to this login page from our private route, we’re passing along this state
which looks like that. But if not, then go ahead and just set the
path that we’re eventually going to be taken to to just the index page. And so now instead of passing a string to
our to prop, what we can do is pass it from. And then now what also we can do down here,
we can say, “You must log in to view this page at,” you could say from .pathname. So now, inside of our app, if all of this
is working correctly, when we go to Protected Page, we get redirected to our login page. And now you’ll notice that we have ” You must
log in to view this page at /protected” because that was the page we were trying to go to. And now when we click on Log in, instead of
being taken to the Public Page, we get taken back to the protected page because that was
the initial page that we were trying to go to. So now the last thing we want to do is when
we are on the Protected Page, you’ll see here in the final app, if we are logged in, we
want to see Welcome with a Sign out button here. And then if we are not logged in and we are
on the index page, we want to see this “You are not logged in” text. So what we can do is let’s head back over
to our app, and we are going to create a brand new component. We can create it right here. We will call it AuthButton, and this is going
to have, kind of, two different states to it. We will say if the user is authenticated,
then what we want to do is we want to go ahead and show them this paragraph, and we will
just say, “Welcome!” And then what we want to do is we want to
give them the option to sign out, which we will talk about here in a second. I’ll just pass a blank function in there for
now. And if the user is not logged in, then we
want to come in here and say, “You are not logged in” wrapping this in a paragraph. All right, so now inside of our main app,
what we can do is below this

we can go ahead and just render our AuthButton. So now when we are… Let’s go to our homepage. When we are not logged in, we see “You are
not logged in.” And then when we log in, what we see is this
Sign Out button. And now what we need to do is we need to figure
out a way so that when we unauthenticate or when we logged out, we get redirected back
to this homepage. Up until this point, when we’ve talked about
redirecting, we’ve used React Router’s Redirect component, but in this case, it doesn’t really
make a whole lot of sense. I guess we could add a…we could change this
into a class. We could add some state to it and then redirect
that way, kind of like we did earlier where we flipped… Where was it? It was right here. But that just seems like a lot of work for
this simple component. So another thing that React Router gives us
is a history object which has a .push property on it, which will basically redirect us as
well or it will take us to another route. The problem with that is this AuthButton isn’t
being rendered by React Router, so we’re not being passed a history prop. So what we can do in order to receive that
history prop is we can use React Router’s higher order component called withRouter. So now all we need to do is we can come down
here. We can wrap our AuthButton inside of withRouter. And then now what that’s going to do is that’s
going to pass us a location match as well as history. And then now inside of this button, what we
can do is we can come in here and say fakeAuth.signout. And then as a callback, we can say once that’s
finished go ahead and call history.push. And let’s just go to the home route. So again, what’s happening here, because we
need access to history in order to call history.push, we use withRouter to wrap our component. That gives us history, and that makes it so
when we log out, we can call history.push which will take us back to the home route. So let’s go ahead and make sure everything
is working here. So we are not logged in. We can see the Public Page, but when we try
to see the Protected Page, we get this right here. So we’ll log in, we get taken back to the
Protected Page, and so we can see any pages that we want now. But when we try to sign out, or but when we
do sign out, we get taken back to the index page and we can no longer access the Protected
Page until we log back in.

Only registered users can comment.

  1. Good video! I'm doing a package that provides some cool Auth functionality, any suggestion?

  2. It would be so great if someone would do a video covering Service Workers with CRA. I've run into so many caching issues with them and still can't figure out what they are, what they do, and best ways to use them. Just an idea.

  3. Really nice vid. Seriously… I am trying to really take in React and it seems like a GREAT framework. I am coming from Angular and Java and this is much cleaner. Thanks also for the great way you created something very very simple and then began adding in more and more functionality. It is much easier to follow this way! you rock!

  4. There''s one flaw here, the login button still shows up if you manually go to /login after being authenticated.

  5. Isn't this approach a really bad idea for security? Your managing state of logged-in/logged-out in the react application, which is in the users browser. Someone could just go into the code rendered in there browser, flip the logged-in flag and then do what ever they want in the application?

  6. How did you solve the problem of "Cannot GET /login" while using BrowserRouter ?
    Edit: If you are using webpack add this into your webpack.config.js file
    devServer: {
    historyApiFallback: true,
    By the way, you need to configure the server side when you want to go in production.

  7. AHHHHHHH!!!!!! THIS IS MADENING! I'm tired of wasting my time buried in tons of videos reading directly from the react-router tutorial. STOP regurjitating the base tutorial. we can all read it on our own. WE COME HERE TO FIND REAL WORLD EXAMPLES. This is not that. WASTE OF TIME.

  8. if this course is going to be cover all of react router v4 , i can say that the author is a awesome guy …..

  9. Can a user gain access to protected routes by the dev tools? Newbie developer here thanks for the video

  10. Good stuff. Definitely helped me work through that example. I was having a bit of a tough time trying to work through it without a proper explanation.

  11. Isn't easier to put ternary in the link or I didn't catch the point here? For instance: <Link to={ isAuthenticated ? '/account/funds' : '/login' } />

  12. How would we check if a user is authenticated via Redux? eg looking for an 'account' object within the Redux store? The fakeAuth here isn't connected to Redux in this example.

  13. Would we just wrap our private route with Connect( ) and reference the global isAuth redux state if we were to implement this with Redux?

  14. Would this method still work if I am trying to pass get user information in other components as well? say I need to be able to access the username in the private route, should I be able to just pass it as props?

  15. In real world, auth happens asynchronous in some cases, this tutorial will become more useful if you take this into consideration

  16. The syntax of renaming destructured props it was driving me crazy because it was first time I saw that, you are the only one who explained that detail, thanks

  17. a little bit hard to follow with other postings, but this video is so easy to follow. Thank you so much for uploading this video!!

  18. 🚀 Try our new 2019 React Course –

  19. Good job Tyler… I like how you easily explain these confusing stuffs. Just a small observation; at 7:08, is there a reason why you could not just say fake.isAuthenticated ? instead of explicitly comparing to true ?

  20. This obviously makes logged in status the condition for redering the protected route.
    This is fine for protection of proprietary content and such.
    What if I need to protect private content, like personal accounts, profiles, user generated data and such?
    How do I make the confirmed (loged in) specific user ID a condition of redering?

  21. Good tutorial, but if you refresh the page you lose the login. That's not really useable in the real world. How do you enable true Login with React-Router that persists, like you would experience in the real world, and have protected routes? None of the tutorials I have seen anywhere on YouTube or elsewhere have answered this question.

  22. this is not working! The AuthButton does not gets refreshed after first time in renders. The value of fakeAuth.isAuthenticated is still false in it

  23. excuse me.. i have a little question, should i import ReactDOM? because while im compiling the code, the result is browser history needs a DOM
    Thank you..

Leave a Reply

Your email address will not be published. Required fields are marked *