‫Now let's implement authorization
‫so that only logged in users
‫can actually access our application.
‫And the way we are going to implement this in practice
‫is by basically wrapping the entire application here
‫into a protected route component.
‫So we actually did something like this before
‫in a world wise project,
‫but here, of course, we are doing it in a bit more
‫real world way.
‫So remember that all of these routes right here
‫are child routes of this layout route right here.
‫Nowt hat means that basically all of these components,
‫so all of these pages, are rendered inside
‫this app layout component that we built earlier.
‫And so what we're gonna do now is to wrap this app layout
‫itself into that protected route component.
‫And so then that will mean that all
‫of these different routes can only be accessed
‫if the protected layout component determines
‫that there is a currently logged in user.
‫Now that sounds more confusing than it actually is.
‫So let's just create that component here in UI.
‫So protected route.jsx like this.
‫And this then will of course need to receive the children.
‫And for now all we are going to do here
‫is to just return the children.
‫And so then everything will work the same.
‫So let's just try this out now.
‫And now we, of course, need to wrap this
‫around the app layout.
‫So just like this.
‫Now these routes here will all be children
‫not only of the app layout but also of protected route.
‫And so in that component we will then only return
‫the children if the user is actually authenticated.
‫So here we will need to take a few different steps.
‫And so let's write them all out here.
‫So first, we need to load the authenticated user.
‫Then while that is happening, let's show a spinner.
‫Then if there is no authenticated user,
‫then redirect to the login page.
‫And finally, if there is a user, render the app.
‫And so that's basically this step number four here.
‫And so now let's do these four here one by one,
‫starting with loading the authenticated user.
‫And so for that, we once again will create a new function
‫here in API auth.
‫Now you might wonder why we actually need a function
‫to load the user from Supabase again
‫if we just saw the user here in the console
‫right after logging in.
‫Now the thing is that the user might want to access
‫this page a bit later,
‫so not only after they have logged in.
‫So in a web application, even if you logged in
‫like a day ago and if you then reload the page,
‫you will still want to be logged in,
‫not only immediately after you do that login process.
‫And so then each time that you reload the page,
‫for example, a day later, then that user
‫will need to be refetched from the Supabase API.
‫And so then we can check if that user exists
‫and if they are still authenticated.
‫And so here we will now create a function called get user
‫or maybe get current user.
‫So for this, first we actually need to check
‫whether there is an active session.
‫So for that we use get session.
‫And so this will actually get that data
‫from local storage that I showed you earlier.
‫So this receives some data, let's rename this to session.
‫And so if there is no session at all,
‫if there is no session.session,
‫which is actually the name, then we just return null here.
‫So then there is really no current user.
‫But if there is,
‫then we can get that user again from Supabase.
‫And once again, you might think that
‫we could just get the user here from the session.
‫And while that is true, it is a bit more secure
‫to just redownload everything from Supabase.
‫So this will get the normal data and error
‫and then, as always, await Supabase
‫then the auth module and then get user.
‫So here, let's lock that user, which is called data.
‫Then here, let's just grab this part.
‫And then we are actually only really interested in
‫returning the user itself.
‫So remember how earlier we saw here an object
‫which had the session and the user?
‫So that session is not really important for us.
‫And so let's just return .user
‫and also just make sure to check that it actually exists.
‫Now as always, we will actually manage this state
‫using React Query.
‫So let's create ourselves a use user hook
‫and then export function, use user.
‫So it will basically get the current user
‫and store it into cache.
‫And so then, it will not have to be redownloaded
‫each time that it's necessary.
‫So here we're gonna just use query.
‫And then from there, we get the loading state
‫which is one of the big reasons why we choose
‫to manage the state always with redd query.
‫Then we get our data
‫which we rename to user and then or error
‫which we're not really gonna use, so we don't need it.
‫So use query here.
‫And then the query, let's start with the key.
‫Let's call it just user.
‫And then the query function
‫will be the one that we just created.
‫So that's get current user.
‫And then from here, let's return the is loading state
‫and the user itself.
‫So the login form we no longer need.
‫The app, let's keep it open.
‫And then here, let's use that custom hook
‫that we just created.
‫So we get the user and the is loading state
‫from use user.
‫Now while this is loading,
‫remember we then want to show a loading spinner,
‫so return spinner.
‫And actually, we should wrap this here
‫into a full page element
‫so that the spinner then really renders
‫here in the center of the page.
‫So let's quickly write that here
‫as a styled component.
‫That we don't have yet.
‫So that's styled from styled components
‫not from React Query.
‫Dot diff.
‫And so let's give it a height of 100 VH.
‫Background color.
‫Here we get one of our variables.
‫Then here, for some reason, we got that code.
‫And then let's just center it using flex box.
‫Center and finally, justify content center as well.
‫And then here, let's just wrap that whole thing in there.
‫Now the most important part is actually this one
‫but let's actually immediately try this out.
‫So I believe we did log in earlier,
‫and so here we should have something,
‫or actually we don't.
‫So let's come to the login page.
‫Here we already have our credentials
‫and so let's log in and notice
‫how we actually got that rotating spinner there
‫like for a split second.
‫Did you see that?
‫And so now here, we do have this current user.
‫And so then here, this function will get that user
‫from the local storage.
‫Then that means that we have a session.
‫And then based on that,
‫we will fetch the current user from Supabase.
‫And so later, we then get that data here into our query.
‫So into our React Query.
‫And so that should now be in here.
‫And indeed, here is all the data that we need.
‫And one of the most important parts
‫is this role here set to authenticate it.
‫And so let's actually here immediately use that
‫to also return the is authenticated data
‫so that we don't have to check it anywhere else
‫but instead, we compute that right here.
‫So user and if they exist, dot role equal authenticated.
‫So that's exactly what we have here.
‫So if this part here is true,
‫then is authenticated will be true.
‫And then based on that, here we can take this decision.
‫So whether the user should be redirected
‫to log in or if the application should be rendered.
‫And so now for the ultimate test, let's try this again.
‫And then we should see that rotating spinner there.
‫So saw that.
‫That was because our user was fetched from Supabase.
‫And now for the final part,
‫if there is no authenticated user
‫then we want to redirect back to login
‫because in this situation,
‫the user is, of course, not allowed into the application.
‫And so that's what redirecting to login basically means.
‫So here we will need the navigate function
‫from use navigate like this
‫but we are only allowed to call this function here
‫inside some other function like in a callback
‫or in a use effect.
‫So not at the top level of the component.
‫And so here, let's just use a use effect for that.
‫So we create our function here.
‫And so here we can say...
‫We don't even need the user here
‫but all we need is that is authenticated state
‫that we created earlier.
‫And so now here we can say if is not authenticated,
‫then we want to navigate to the log in page.
‫But actually, this is not even enough
‫because in the beginning, while we are still loading,
‫the user is also not authenticated yet.
‫But that doesn't mean
‫that we want to redirect them to the login page.
‫And so here, let's also say and is not is loading.
‫So basically when we are no longer loading
‫and then the user is not authenticated,
‫then that means that they are not allowed
‫into the application.
‫And so then we redirect them to the login page.
‫Now here, thanks to this error message,
‫we can again prevent some big mistake
‫which would be to call this hook here conditionally.
‫So this is your condition.
‫And so that would then change the call order
‫of our react hooks, which remember, is not allowed.
‫And so that's why we have these ESLint rules
‫that prevent us from doing that.
‫So let's just change the order here.
‫And then here we need to also give this effect
‫all the things that it needs.
‫So is loading, and also the navigate function.
‫And now I believe that we actually have everything here.
‫In the end here let's just make sure
‫that this really only get returned if is authenticated.
‫So only then return these children,
‫which again, is just the application itself.
‫So let's reload and we are still logged in
‫and so, beautiful.
‫And I guess that if we remove this access token from here,
‫so from local storage,
‫and you can do that or you also don't have to,
‫then immediately once we go back to the app,
‫we are redirected to the login page.
‫So this means that indeed the logic
‫that we just wrote is working.
‫So here we do have the user but we see that it is null,
‫so it doesn't exist, basically.
‫And the reason for that comes from here
‫because the session does not exist.
‫But now let's indeed log in again and well,
‫nothing happened.
‫So we should have moved now actually to the dashboard.
‫So let's just manually reload here and try that again.
‫And great.
‫So that does actually work.
‫We just had to reload the page here.
‫Now maybe you noticed that we still got
‫that rotating spinner there.
‫So let me show that to you again by deleting this here
‫which is effectively logging out.
‫And so then if I reload,
‫then it automatically gets me here.
‫Let's just make sure again by manually loading
‫and then watch what happens as I click here.
‫So for a short period of time,
‫you will see the spinner rotating there.
‫Saw that?
‫Now in this case, that's not really necessary.
‫It is necessary if we come back later to the page
‫like so, then here, React Query will need
‫to refetch the user's data.
‫But immediately after we logged in,
‫that data has just been downloaded at that very moment.
‫And so in that situation,
‫it's not necessary to then run this again,
‫so running this get current user again.
‫Instead, React Query could simply get this data
‫from the cache if we put it there immediately
‫after logging in.
‫So that would be a really nice thing
‫and make the login a little bit quicker.
‫So it's not 100% necessary to do this
‫but I think it's a good idea to do so.
‫And so let's come in here to use login.
‫And so on success,
‫what we're going to do is what I just said.
‫So we will take the newly logged in user
‫and manually add them to the React Query cache.
‫So for that, first of all, we need again our query client.
‫And so with this,
‫I will show you yet another really great feature
‫of React Query.
‫So use query.
‫It's use query client.
‫So this one we do not need.
‫And then here on that query client
‫where we also called things like invalidating queries
‫or prefetching queries, we can also use set query data.
‫And so then we just specify the query key.
‫And so that is user and then the value.
‫And so again, this basically allows us to manually
‫set some data into the React Query cache.
‫And so then here in this use user that will be called later
‫and which uses the same query key,
‫React Query will then simply get this data from the cache,
‫so just like in all other situations.
‫So let's try that.
‫Let's delete this from here.
‫And then immediately we are greeted again
‫with our login page.
‫And now as we log in, we shouldn't see
‫that rotating spinner.
‫And well, it actually was there
‫but I believe that React Query did not refetch that data.
‫At least it shouldn't have.
‫So let's clear all of this here.
‫And this is not that important.
‫This is just a bit for fun, so to say.
‫So let's reload and then let's see how many network requests
‫are going to be made.
‫So probably a lot of them, but let's just see.
‫So this one here is probably the login itself
‫and then here maybe the user was actually refetched again
‫so I'm not really sure about that.
‫But in any case, really what I wanted to do here
‫mainly was to show you this feature
‫so that we can also manually set some data
‫into React Query's cache.
‫So let's just come back here to the application again
‫and I will delete this one last time.
‫And I promise this is the last time,
‫because in the next lecture,
‫we will actually implement user logout.
‫But in any case, let's just do this one more time
‫because now I want to show you
‫that we forgot to do something earlier.
‫So in these situations where the credentials are wrong,
‫then here after that is wrong,
‫we actually want to delete these inputs here.
‫So it's not normal that this password and the address
‫stay there in the field after the error.
‫So let's fix that.
‫And I believe here we can already close all of this.
‫So we implemented all of this successfully,
‫including this component right here,
‫this very important one.
‫And now let's come back to our login form
‫and then add some option here to this login function,
‫'cause remember that this is a mutate function.
‫And so we can set some options here,
‫for example, the onsettled handler.
‫And in this case here,
‫we cannot add this right into use login.
‫So we cannot clear these fields here
‫because of course we don't have access to
‫these date variables here.
‫And so therefore we need to do that outside.
‫So all we need to do is to set email
‫and set password back to these empty strings.
‫So let's try that, write something else.
‫So that's a lot nicer.
‫And now it does work.
‫Beautiful.
‫So we have in this short period of time,
‫at least relatively short,
‫implemented both authentication and authorization
‫and all on the back of this really great Supabase feature
‫which makes it really, really easy
‫to add this very important part
‫to all our web applications.
‫And now moving on, as I promised,
‫we will implement the logout functionality.