
No Comments Yet
Be the first to share your thoughts and start the conversation.
Be the first to share your thoughts and start the conversation.
How did you manage to remove the blur property and reach here?
Upgrading gives you access to quizzes so you can test your knowledge, track progress, and improve your skills.
By logging in, you'll unlock full access to this and other free tutorials on JSM Pro.
Why? Logging in lets us personalize your learning experience, track your progress, and keep you in the loop with new workshops, coding tips, and platform updates.
You'll also be the first to know about upcoming launches, events, and exclusive discounts.
No spam—just helpful content to level up your skills.
If that sounds fair, go ahead and log in to continue →
Enter your name and email to get instant access
In this lesson, we explore the step-by-step process of implementing an authentication user interface (AuthUI) along with Google authentication in a React application. The session covers routing setup, UI design, and functional aspects of handling user authentication, including error handling and redirect strategies.
00:00:02 To get started with AuthUI, let's first create a route for the Auth page.
00:00:08 So head over to App, and notice how currently we have the routes right here for the admin.
00:00:15 But now we'll create it outside of the admin layout, which means that this page won't share the layout we created for the admin dashboard,
00:00:23 because it doesn't have the header, the left sidebar, the navbar, or whatever.
00:00:28 It just has a singular login.
00:00:31 So I'll create it right here within a new folder called root.
00:00:36 And within root, I'll create a new file called sign-in.tsx, within which I'll run RAFCE.
00:00:45 Now we'll have to head over into routes.ts because this doesn't just work like Next.js' file-based routing.
00:00:52 You still have to define it right here.
00:00:54 So above the current layout, I'll add a new independent route pointing to sign in, and its path will be routes root signin.tsx,
00:01:07 like this.
00:01:08 So now, if you head over into that route, we can also try accessing it on the dashboard by heading over to sign in.
00:01:16 And there it is, sign in, cannot read properties of null.
00:01:20 So let's actually implement it.
00:01:22 If I reload it one more time, the error is gone.
00:01:25 So I believe we should be good.
00:01:26 I'll start with the UI.
00:01:29 So I'll turn this div into a main and give it a class name equal to auth.
00:01:34 What this will do is it'll automatically apply the background photo right here.
00:01:39 Looks okay on mobile, but once again, it really stands out on desktop.
00:01:44 If you want to check out how I did it, the only thing you have to do is basically apply a full width, a full height, and then there's this background-auth,
00:01:53 background-cover, and background-null-repeat.
00:01:56 And this image is taken over right here from our assets.
00:02:00 We have just added it as a CSS variable right here within Tailwind.
00:02:04 So now I'll create a new section within this main, and this section will have a class name equal to size-full, glass-morphism,
00:02:17 flex-center, and the padding X of 6. This will basically create this glassy feel over the entire background.
00:02:26 So the card is more visible.
00:02:28 So within this section, I'll create a new div with a class name equal to sign in card.
00:02:37 And within it, I'll create a new header with a class name equal to header.
00:02:45 Within this header, we can render a React router link.
00:02:50 So make sure to import it.
00:02:52 And we can point it to forward slash, meaning just the homepage.
00:02:55 And within it, we can render our logo.
00:02:58 So I'll render an image with a source of assets.
00:03:03 forward slash assets, forward slash icons, forward slash logo.svg with an alt tag of logo and a class name equal to size of 30 pixels.
00:03:17 There we go.
00:03:18 And below that link, we can render an H1.
00:03:23 That'll say Tour Visto, which is the name of the application with a class name of P28 Bold and text-dark 100. Thankfully,
00:03:36 I added the Tour Visto name to our Webster dictionary.
00:03:39 So now, even when I misspell names, I know I misspell them.
00:03:43 There we go.
00:03:44 Below this header, we can create the article for the rest of the card that'll have an H2 And this can say something like,
00:03:52 start your travel journey.
00:03:57 We can style it a bit by giving it a class name equal to p28-semi-bold, text-dark 100, and text-center.
00:04:09 And below it, I'll also render a p tag that'll say something like, let's see what do we have in the design.
00:04:17 sign in with Google to manage destinations, itineraries, and the user activity with ease.
00:04:25 So, I'll copy that from the design and paste it right here.
00:04:28 I'll also give it a class name equal to p18regular text-center text-grey100 and exclamation mark leading dash 7. So this will change how the characters
00:04:46 are structured.
00:04:47 Right below this article, I want to render a button.
00:04:50 And this button will come from Syncfusion.
00:04:52 So I'll say Button, Component, coming from Syncfusion.
00:04:57 Right at the top, that is Syncfusion EJ2 React buttons.
00:05:01 And we can render an image right within that button.
00:05:05 with a source of forward slash assets, forward slash icons, forward slash google.svg.
00:05:13 Within it, I will also render an icon CSS, that'll be E search icon, so we style it further, with a class name of button class.
00:05:26 exclamation mark H11 for the height, and exclamation mark W full.
00:05:32 Sometimes you have to add the important style to the class names so that they're actually taken into account.
00:05:38 And now you'll see this huge Google G.
00:05:40 So let's instead give it a class name of size-5 to make it smaller.
00:05:46 And I just noticed that I applied some styles to this image right here, but those styles were actually meant to be applied to the button itself.
00:05:54 So I'll move them up and say, this button will be of a type button with the icon CSS, a class name, and then on click.
00:06:08 equal to handleSignIn.
00:06:12 So right at the top, I'll declare this handleSignIn function as an asynchronous basic function for which the logic will implement very soon.
00:06:23 But now what matters is that we have this button.
00:06:26 Within it, we have this image.
00:06:29 We can also give it an alt of Google and below the image we can render a span that will say sign in with the Google and we can give it a class name of
00:06:45 P dash 18 dash semi-bold and text dash white, so we can better see it on this blue button.
00:06:52 There we go.
00:06:54 Sign in with Google.
00:06:55 Now, the only thing we have to do is implement this handleSignIn function, which right now will be super simple to do.
00:07:02 Actually, believe it or not, we have already done it.
00:07:05 So right here at the top, the only thing you have to do here is say await, loginWithGoogle which basically renders this entire function not needed.
00:07:18 So instead of declaring this handleSignIn function, what we can do is just head down and call the loginWithGoogle right here.
00:07:30 when the button is clicked.
00:07:32 But there is one thing that we have to add at the top though, and that is a loader.
00:07:37 See, in React Router, a loader is an asynchronous function tied to a route, and it runs before the route's component renders,
00:07:47 and provides the data to that component so that it can use it immediately once it appears.
00:07:53 This makes the app feel faster and more structured because data fetching happens before the UI shows.
00:08:01 So to implement this very cool React router loader, you can do it right at the top of the sign-in function.
00:08:09 Export async function client loader.
00:08:14 You can open up a try and catch block.
00:08:19 In the catch, we can simply console log the error, saying something like error, fetching user, and in the try, we'll actually try to get the user data beforehand.
00:08:31 So we'll say const user is equal to await account.get.
00:08:39 And then if there is no user.$id, we'll simply return a redirect coming from React router.
00:08:49 to the home page.
00:08:50 And if we get the user, that's great because then we'll already have access to it before.
00:08:55 And we also have to import this account functionality from AppRight Client.
00:08:59 So now if you reload, you can see that it loads super nicely.
00:09:03 And we can also copy this client loader and also add it to our admin layout.
00:09:10 But we'll change it up just a tiny bit.
00:09:13 Within the admin layout, head over above the current admin layout component and paste this client loader.
00:09:21 Here, we'll do something a bit differently.
00:09:23 Keep in mind, this will render when we're on the dashboard page.
00:09:28 So here, we want to check AppWrite's auth for the currently authenticated user, And if there is no authentication, redirect user to the sign in.
00:09:38 So we'll do account.get.
00:09:40 If there is no user ID, then we'll redirect to sign in.
00:09:45 So a bit differently than in the other one.
00:09:47 But if there is an existing user, so const existing user is equal to await get existing user coming from.
00:09:58 app.write.auth.
00:09:59 To it, we have to pass the user.$id.
00:10:04 Then we can check if existing user?status is equal to user in that case we again want to redirect like this to the forward slash why because regular users
00:10:21 should not be able to visit the dashboard only admins can so this is another check to see if we need to reroute them somewhere else finally we'll return
00:10:33 existing user question mark dot If we have it, we'll return the data for the existing user.
00:10:40 Else, we'll say await store user data, like this.
00:10:46 Here, I am missing user.
00:10:48 And here, instead of saying error fetching user, I'll say error in client loader.
00:10:54 And I'll return the redirect to sign in, because most likely we have to sign in if we experience the error fetching the user.
00:11:03 What you can do now is open up your terminal, expand it a bit, and stop it from running.
00:11:10 That way, all of these changes regarding routing will be applied, so you can then rerun your application by running npm run dev,
00:11:18 which will spin it again on localhost 5173. If you do this, and if you head over to forward slash dashboard, you'll notice that it'll automatically redirect
00:11:29 you back to sign-in, which means that our redirects and authentication are working.
00:11:34 Now, just before we click this Sign in with Google button, let's head back to AppRide to make sure that all of our settings are correct.
00:11:41 As of recently, AppRide is making a lot of improvements to their infrastructure.
00:11:46 and one of those improvements are the regions.
00:11:49 Right now, Frankfurt is one of the primary ones, but in the future, there could be more.
00:11:54 So depending on which region is closest to you, you'll need to click on it right here to copy the endpoint, and then you'll have to use what you copied
00:12:02 over right here as the AppRite endpoint.
00:12:05 Since I'm in Frankfurt region, for me it's FRA.
00:12:09 Alongside that, we can head back over to Auth, head over into Settings, and look for Google.
00:12:17 We have already added our App ID and Secret before, but I think I forgot to enable it.
00:12:22 So click Enable.
00:12:24 recheck your app ID and app secret over from Google.
00:12:27 On Google, you can also head over to the client you created and remove the authorized JavaScript origin for 5173 localhost.
00:12:36 It's not needed since we have this AppRite redirect.
00:12:39 And once again, just copy the URI from AppRite and paste it over right here to make sure that you have the same exact one.
00:12:46 As of recently, I think they're also adding the region at the start.
00:12:51 Once you do that, click save and also head over into your branding and make sure your app is published.
00:12:57 If your app is not published, somewhere on this page, you should see a publish button.
00:13:01 So once you do that, you'll be able to upload the logo of your application to further customize how your authentication behaves.
00:13:09 So if everything is looking good on the Google side, click Update right here on AppRide to confirm our setup.
00:13:16 Just like that, Google Authentication has been enabled, so you can head over to our application and click Sign in with Google.
00:13:24 And just like that, Google Authentication has been implemented.
00:13:27 In case you want to further customize your workflow, you can do that by implementing your app domain and your app logo so it shows up on Google,
00:13:35 so the people know what app they're signing in to.
00:13:38 But with that said, I'll just sign in.
00:13:40 If you do that, you can notice that we'll be redirected to localhost 5173. And now, if you try to be sneaky and manually navigate over to the dashboard
00:13:50 to be able to see what admins are seeing, check this out.
00:13:53 You'll automatically be redirected to the public-facing homepage, which right now is completely blank.
00:13:59 And if you navigate over to Sign In, you should be redirected back to the homepage as you're already signed in, but it looks like that redirect is now working.
00:14:09 So if you head back to your Sign In page, it looks like we need to reverse this operation.
00:14:14 If there is a user already logged in, then redirect to homepage.
00:14:19 So if you save this and now head over to Sign In, you can notice that since we're logged in, we can no longer see the login page.
00:14:27 Perfect.
00:14:28 But now, hey, how do we actually continue developing the rest of our dashboard, finally, that we're logged in, since we are now being redirected?
00:14:36 Well, let's give ourselves admin permissions.
00:14:39 Head over to your app, right?
00:14:41 Databases, travel dashboard, users, and notice this one single user right here.
00:14:49 If you look at its data, you'll see my name, email, and account ID, the image URL as well, joined ad, and then at the end,
00:14:58 there's a status.
00:14:59 It's either a user or an admin.
00:15:02 So I'll switch it over to admin, save it, and head back over to localhost 5173, and navigate over to Dashboard.
00:15:12 If you do that, you can notice that now we can see the dashboard and we're no longer getting redirected.
00:15:18 Perfect.
00:15:19 This means that the entire sign-in and account creation process are working properly.
00:15:24 Let's also hook up the logout functionality so we can test the full circle of logging out and then authenticating one more time.
00:15:32 To do that, we can head over into our NavItems component and right at the top of it, we can try to access the user data to replace this dummy user.
00:15:41 I can do that by saying const user is equal to useLoaderData.
00:15:47 And this is coming directly from React Router, so this is a new functionality.
00:15:52 But wait, how does this useLoaderData know exactly what data to fetch?
00:15:57 From where and why did I set it to be equal to the user?
00:16:01 Well, let me show you.
00:16:02 The useLoaderData gets the data from the loader function of the nearest route.
00:16:08 Now, the navItems component itself is not necessarily a route, but it is used within our admin layout.
00:16:17 So if you head over to the admin layout, you'll see that here we have a client loader function that returns only one thing.
00:16:26 What is that?
00:16:27 The existing user.
00:16:28 So that's why we know that we can fetch that user right here.
00:16:32 Pretty cool, right?
00:16:34 Alongside the user, we can also get access to the navigate functionality coming from the useNavigate hook, also provided to us by the courtesy of React Router,
00:16:45 which now is working much more similarly to Next.js, which of course I embrace.
00:16:51 And then here, we can handle the logout functionality.
00:16:55 it'll be equal to an asynchronous function where we want to await the call to the logoutUser function coming from AppWriteAuth.
00:17:05 And then after that, we simply want to navigate over to forward slash sign in.
00:17:10 Now, let's also render the real user information.
00:17:13 So, right here, we have the username and user email.
00:17:16 I think it's already done, right?
00:17:18 Because we're now fetching it from the real user instead of the fake user data object that we had before.
00:17:23 The only thing we have to do is on click, instead of this console log, we want to call the real handle logout.
00:17:30 So if I now save this, head back over into the dashboard, we'll see that we now have a real Adrian name right here with the real email,
00:17:39 but the photo is missing.
00:17:40 So to fix it, I Googled Google profile photo not loading in Vite React development.
00:17:47 So just trying to see what would be the reason that even though we have the access to the actual URL of the photo, and I know we have it because I console
00:17:55 logged what was coming back from that photo, if I then head over into it, you'll see that it's actually publicly accessible online,
00:18:02 but for some reason, it wasn't showing within our application.
00:18:05 So, I Google that, and then if you head over to the response, it'll say that by adding refer policy of no referrer to the image tag,
00:18:14 you can solve the Google image not showing.
00:18:17 So just add the refer policy of no referrer to this image where we're rendering the image URL.
00:18:26 If you do that and go back to your localhost, you should now be able to see this image right here.
00:18:30 Perfect.
00:18:31 So finally, let's test out the logout functionality.
00:18:35 If I click it, I get redirected back to sign-in.
00:18:38 Now, I'll head over to the dashboard manually, and you can see that I can't see it.
00:18:44 I immediately get redirected to the sign-in.
00:18:46 Can I maybe go to the localhost, just the route route?
00:18:51 Well, yes, because currently there's nothing on there.
00:18:53 Later on, we'll implement the redirect from there too.
00:18:56 But now if I go ahead and sign in, okay, now we got redirected to the homepage.
00:19:01 Later on, we'll implement a great public facing website right here.
00:19:05 But for now, let's head back over to our admin dashboard since we have the full privileges to it.
00:19:10 And one thing that I noticed is that right here, even though it says your name, it's not the same name that we have here.
00:19:17 It's still using the one from Constance.
00:19:19 So to fix this, we'll have to use the React routers prefetching one last time for now.
00:19:26 So would you know how to do it based on how we implemented it previously?
00:19:30 If not, I'll show you how to do it one more time.
00:19:32 First, we have this additional function that we create.
00:19:36 Export async function, client loader.
00:19:41 Within it, it allows you to prefetch some data you need on that page.
00:19:45 The only thing we need is the user.
00:19:47 So I'll say const user is equal to await get user, like this.
00:19:54 And this getUser is coming from AppWrite Auth.
00:19:58 So make sure to import it from there and then simply return it.
00:20:02 Or in an even simpler way, you can just say return await getUser.
00:20:09 Or if you want to be really cool, you can turn this over into an ES6 arrow function by saying exportConst clientLoader is equal to an asynchronous arrow
00:20:24 function with an immediate return.
00:20:26 So you can just skip the return statement and the braces and just say return await getUser.
00:20:33 And with that, you can turn this client loader into a nice looking one-liner, which fetches the user.
00:20:40 And now you can retrieve it from within your page.
00:20:43 Just right here under params, you get access to the full loader data.
00:20:49 And we also need to assign a type to it.
00:20:52 This type will be provided to us by React router.
00:20:55 So say router, or rather route.component props.
00:21:01 And we can import this type.
00:21:05 So saying import type route in curly braces from dot slash plus types forward slash dashboard.
00:21:15 If you do that and remove these curly braces, because we don't need them as we're not within an object, You can see that now our TypeScript knows that
00:21:23 the loader data will contain the data returned from the loader or the client loader, which in this case is the user.
00:21:30 So, how do we now accept that user?
00:21:32 Well, the only thing we have to say is const user is equal to loader data, and we can even assign a type to it by saying as user or null,
00:21:43 if it maybe doesn't exist.
00:21:45 Now, it looks like TypeScript is still complaining, saying that this could be unknown.
00:21:49 But that's not really the case, because we know what we're going to get back from the client loader.
00:21:54 Oh, but it looks like I forgot to add an export statement right here.
00:21:59 If you add it, you'll see that it'll no longer complain, and it knows exactly that the username is either a string or undefined.
00:22:07 Perfect.
00:22:08 So with this in mind, we are good to test it all out.
00:22:11 So if you head over to your dashboard, you can see that at the bottom left, we have the username and now it says, welcome AdrianJSMastery right here at
00:22:19 the top, which means that we're successfully gathering the user data and we're successfully signed in.
00:22:25 So with that, we have now implemented the full circle of authentication.
00:22:31 everything from the UI to functionality to logout, and also fetching the user data and storing it within the database.
00:22:38 So if you head over to AppRide, you can already see that we have this user that we created.
00:22:43 But if you also head over to Auth, you'll see that we have created a user over there as well.
00:22:48 So not only have we implemented the full authentication, but since we have the user in the database here, that means that now we're also successfully creating
00:22:59 documents within our database collections.
00:23:01 Which means that we can also not only fetch them to show the username on the left sidebar or the dashboard, But rather, we can render a full table showing
00:23:12 all the users that have joined their application so far and display their statuses.
00:23:17 They can either be users or admins.
00:23:20 So in the next lesson, let's focus on implementing the users table.