Now I want to further improve our authentication by implementing custom login screens. So first of all let's go ahead and let's go inside of source features and let's create a new feature which we are going to call out and inside of here we can keep some out specific stuff. Let's start by creating a utils.ts inside of it. Inside of the utils let's go ahead and let's import redirect from Next Navigation and let me just expand my screen so you can see. So redirect from Next Navigation and we are going to import out from out and let's export const protectServer, an asynchronous method which we are going to reuse in all server instances.
So const session will use await out. If we have no session, very simply we are going to redirect to slash api slash out slash sign in. And now let's go ahead go back inside of our root page.tsx so inside of source app we have page here and instead of doing this let's go ahead and do the following So I will simply write you are logged in. This is what I'm going to write. So if I refresh this page it says you are logged in.
So now we're going to do the following. We're going to simply add await protect server from features auth utils. So this still has to be an asynchronous method. And if you're logged in you're gonna be here even after you refresh. But if you go to slash out slash API slash out slash sign out and confirm you can see that you are immediately redirected to sign in with GitHub so if I try to go to localhost 3000 you can see I'm redirected back but if I try to go to example editor 123 I will be able to get in, let's just wait a second for the page to compile.
It's not going to be this slow in production, right? This is only in development because it needs to compile the entire page on the first hit now. There we go. So in here I can, for example, access the page. But we want to protect that as well.
So let's go ahead and go inside of our editor here. Project ID page.dsx let's turn this into an asynchronous method as well and very simply await protect server from features out utils and I like to separate my features like this. There we go. Now you can see that this is protected as well. So only after I sign in with my GitHub will I be able to see the homepage and my editor 123.
I'm missing a slash here. There we go. So only after I log in, am I able to see the pages? Perfect. So what I wanna do now is in case I am not logged in, so API out, sign out, I wanna create a separate login screen, right?
Because I don't like this one and I want to use a custom one. So let's see how we can do that. Let's go inside of our source here, inside of the app, and let's go ahead and let's create a new route group, which we are going to call auth. And inside, let's go ahead and let's create a sign-in page. And let's add page.dsx inside.
Now in here, I want to add redirect from Next Navigation and I want to add auth from add slash auth. Let's go ahead and define the signInPage to be an asynchronous function and let's export default sign-in page and what I'm going to check is if we have the session or not. So if we try to visit the sign-in page while we have the session we are simply going to redirect the user back to the home page like this. Otherwise let's return a div sign-in page. Let's go ahead and try it out.
So if you are logged out, you should be able to go to localhost 3000 slash sign-in. There we go. Sign-in page. And you can of course name this route whatever you want. So if you don't want to call it sign-in, you know, you can just call it login or whatever you want.
There we go. And now what I want to do is I want to go inside of the where is my auth.ts file right here and let's go ahead and let's add the pages option and let's change the sign in to go to slash sign dash in like this. So now if you try and go to the root page for example you get redirected to the new sign in page, right? So if I go ahead and also try to manually go this time to slash slash API slash out sign in, this will also redirect you to what we defined as the sign in page here. So that's how we override the default sign in page so that's what we have to develop now so let's go ahead and let's create the a component which we're going to call sign in card and I want to have it separately inside of the features here so let's go inside of the features out here and let's go ahead and create the components folder and a new file a sign-in card dot tsx like this and inside of here, we're just going to export consign in card and return a div, sign in card, like this.
And then let's go back inside of our app here inside of AuthRouteGroup sign in page and now we can just render the sign in card and self-close it so it's gonna be Features.AuthComponents.SignInCard like this there we go, now that's what we render the sign in card great So now I wanna go ahead and style this. And let's style it by first adding a component from chat-cn. Also we have two terminals open we can close that now. Right so just hold one open. Let's do bunx chat-cn ui at latest add card.
So that's what we are going to need right now. Let's do bun run dev. Let's refresh this and now let's go ahead and let's import everything we need from the new card component. So we need card, card title, card header, card content and card description from add components UI card. Great!
Inside of this, instead of using a div, we're now going to be using the card itself. Let's add a card header here. Let me fix the syntax error. And we're going to go ahead and say login to continue here below that we're gonna have a card description which will say use your email or another service to continue there we go And now let's go ahead and let's add a card content here. And inside of this card content, we're going to create the buttons to log in with OAuth providers.
We are gonna add credentials, but first we have to, you know, style our existing login methods, which are GitHub and well, only GitHub for now, right? So inside of card content, we're gonna add a button component from components UI button. And this button will show FA GitHub icon you can import that from react-icons FA like this and FA GitHub will also have a text continue with GitHub. All right, so we kind of prepared the basic content here and let's also inside of the card content, let's just add, how are we going to do this? All right, let's do it like this.
Let's wrap this inside of a div because we're gonna have multiple social providers, right? So I'm going to give this a space y 2.5 because we're gonna have two buttons right the other one will be FC Google and you're gonna have to import that from FC There we go and change this to continue with Google. You can of course choose which one goes first. And now outside of this div, we're going to add a paragraph which will say don't have an account. And we're going to fix this error here by using the appos escape like this so don't have an account and then we're gonna go ahead and add a link which will have a span and it's gonna say sign up and we have to import link from next link so just add that let me move that to the top alongside react icons here and the link needs to have an href which is going to be slash sign dash up like this.
There we go. Now let's go ahead and let's style the paragraph itself. So class name text extra small and text muted foreground and for the span we're gonna go ahead and give it the class name of TextSky700 and hover underline. Like that, Great. And now let's go ahead and give the card content some styles.
So card content is going to have a class name of space Y5, PX0 and padding bottom of 0 like this. And now I want to go ahead and style the card header here. So card header will also have a class name which will be PX0 and padding top of 0. And the card itself will have full width, full height by default and padding of eight like this, great and let's see what else can we improve here so our card header is here, alright our card content here is also alright okay so let's leave it like this for now we're gonna go ahead and modify this later so now what I wanna do oh, also yes, I'm noticing something is wrong so the card description should be inside of the card header like this and Login to continue should be inside of card title like this. There we go.
So that's what I wanted to achieve. Great. So now, well, we have kind of a problem, right? As you can see, this takes up huge amounts of space. And first of all, let's add the rule that these two always need to be one below another so I'm gonna give this div flex flex call and then I can change space to use gap instead like this.
There we go. And now let's go ahead and let's go inside of page here and what we're going to do is we're going to wrap this inside of a div. Like this. And the div will have a class name hFullFlexItemCenter and justify center. And let's see if this did any change.
So if I refresh here, or it's when nothing appears to have changed. So that's because we also have to kind of limit how far this can go. So this is what we are going to say. By default it will be full height and full width that's going to be the default right and let me just zoom out slightly so you can see like this and then once we hit medium breakpoint height will be auto and also width will be limited to 420 pixels. Like this.
And let's see if that improves it in any way. Alright, so we definitely now have a limit but not exactly what I intended and I think I know why. So this is what we're going to do. I'm gonna remove this from here and I'm gonna copy these two. So in the first div, it's just flexbox.
And then in the other div, we're going to have this. Like this. And let's give this by default, full height, full width of the parent. But if we hit MD, that's when something else will happen. So let's try this again.
There we go. So this is how I want it to look like on desktop. You can also zoom in a bit right on 100% this is how it will look like. But if we reach mobile devices it will simply go full screen right. So it should never actually be like it should never look like this because there is no screen that is this small, right?
It should maybe look like this on iPhones, on the smallest iPhone SE, for example. But on desktop, it will look like this. It will be centered. Great! So now let's go ahead and let's actually go back inside of the sign-in card and let's style these buttons a bit.
So I'm gonna go ahead and give the button here a variant, outline, size large, class name, full width and relative. Now let's give the FC Google a class name. Margin right of 2, size of 5, top 2, left 2.5, and let's also add absolute. So this positioning actually makes sense like this. And let me see, so this top to be honest kind of looks a bit off so how about I add top 2.5 or maybe 3 I think 2.5 might be exactly in the center great And now I want to do the same thing but for the other one so we can copy the variant and the class name here and we can copy the entire class name for the icon like this.
Size 5, 2.5. Great. I feel like now they are kind of in the middle of the button here. Great. So we now have continue with Google and continue with GitHub.
And let's actually go ahead now and mark this component as useClient here so that we can add some dynamic onClicks here so I'm gonna go ahead and create a method called const onProviderSignIn which will choose the provider between github and Google and it's going to call sign in but be careful you might be thinking all right great so I can import sign in from auth right? Because that's what we add here. Well, not exactly. Sign-in from auth is not used for client components, only for server components. This will not work.
Lucky for you, there is a solution. Can simply import sign in from next out and not specifically next out my apologies next out react and go ahead and add sign in and pass in the provider there we go and also add a callback URL which technically we don't need because the page itself will redirect but you know if you want to be explicit you can add this and then let's add on clicks here so on click for Google will call on provider sign in Google and on click for GitHub will call on provider sign in GitHub like this. So if you try and click on Google you will get well nothing but you are going to get an error in the terminal I think because we don't have Google set up yet. So go ahead and try and click on GitHub and this should log you in. So let's just wait a second.
There we go. You are now logged in. Great. So if I go to manually API out, sign out again, and I'll sign out, I'm redirected back to this page. Perfect.
So now I want to create also the sign up page because right now it's a 404. So you might be wondering why do we need a sign up page? Well, we need a sign up page in case user wants to use something that's not OAuth because we're going to add credential login later, right? We're going to have username and password and for that you need a separate form to enter your password, to enter your name and things like that. But for OAuth, you can actually use this both to register and to log in again.
That's the great thing about OAuth. That's why I really like OAuth. And I personally would recommend using only OAuth providers with NextAuth. Because you can leverage these big players like Google and GitHub which is essentially Microsoft. You can leverage their spam protection, their two-factor authentication, their email verification, all of those important things, right?
So these are the only two methods which I actually allow on my platform and I also use NextOut. But I am going to teach you credential login simply because a lot of people wondering how to do that with NextOut. Great. So before we continue, I meant before we wrap up the chapter, there is a couple of more things we want to do. So let's go inside of the app here.
Let's go inside of out and let's copy and paste sign in and let's add sign up page right here. And let's rename this to sign up page which will have the exact same logic of redirecting here and in here we're gonna have, you know, sign up page and now what I want to do is I want to create a copy of the Where is my features? Auth components sign-in card. So let's copy and paste this and let's call this sign up card. Let's rename it sign up card.
And if you want to, you can rename the method as well, onProviderSignUp, and then call onProviderSignUp here and onProviderSignUp here. But the only thing we can change now is the title here. So inside of the sign up card, change the card title to be create an account and card description. Well, it can be, you know, exactly the same. It doesn't matter.
And in the footer here, instead of telling the user, you know, you don't have an account, we're going to do the following. We're going to ask them already have an account. And we are going to link to sign in and the link will be slash sign in like this. So now if you click on sign up Oh, we forgot to actually use the sign up card, my apologies So go inside of Auth, sign up And instead of using sign in card, use the sign up card From the same, you know, path All right, let's try it again There we go Now it says create an account and if I click sign in it says log in to continue. Great.
So we now have these two different cards and you're probably noticing one thing. We have the exact same code inside of sign in page and sign up page. So these two things, right? They are exactly the same. So what we can do is we can leverage route group here.
That's why I created the route group. Well primarily I like it because I like to keep my things inside of folders. So I want to know my out is here. I don't just want it scattered around. So I'm going to go ahead and add a layout.tsx inside of here and this way we have ejected out from any other layout which we're going to have on this level of route segments so what we are going to do here is create out layout and before we write anything here let's create an interface out layout props and let's add children here so out layout props will accept the children and inside what we are going to do, very simply, we're just gonna copy from either sign in or sign up, just copy these two divs, right?
Basically our layout. And inside of this one, you're going to render the children and don't forget to close the topmost div. There we go. Now we have our layout and now we have, you know, kind of double centering here. So what we can simply do is go inside of page and you can now remove everything except the card so you can just you know directly return the card inside of the sign-in page and the same thing inside of the sign-up page so you don't need these two anymore because they are exactly the same in both.
There we go. So you can now just render the differences. Perfect. And it should still be centered so you can now refresh and it's going to be centered. Great.
So what I want to do now is I want to add a little background and I want to make it a bit more stylish. So I want you to find, you know, any image you want for your background. You can use Unsplash.com to find a bunch of free images. So I downloaded an image from Unsplash. I'm just gonna paste it here in my public folder.
So you can also copy it from my source code right here. So it's just some random, I don't know, poster wall, right? So let's go ahead inside of, you can, you know, for, for, for development, you can use literally anything as a placeholder, right? So my format of the image is, let me go ahead and zoom out. So a thousand, 20 times, 14, 400, right?
So you can go ahead and create this in your editor if you want to you can use the editor to create an image and simply save it as jpeg and now I want you to go back inside of the actual layout so app out Let's go inside of the layout here and now we're gonna have to add that image. So let me go ahead and expand this and the first thing I'm going to do is I'm gonna add the image as the background here. So I'm gonna add a class background and I'm gonna open the curly brackets and I will directly write URL slash background dot jpeg like this. Let me go ahead and zoom out. Perfect.
So now we have our background set here and now I'm gonna define some rules for the background. So background top, background cover so it never stretches like this and let's also define that the flex will be flex call like this that's also important for me here And here's what I actually want to do next. So I'm going to copy the item center and justify center. And I'm going to add it in a div below that, like this. And then I'm going to move this other div inside of it.
Like that. And let's give this full height and full width. So now we should... Oh, we also have to add flex here. Flex call again.
There we go. So let me expand so you can see. So we are just separating the top background here and we have to kind of create this double effect for this reason. You're going to see in a second. So we have to give this a Z index of four.
Basically anything above one. And now what I want you to do is I want you to go outside of this div, so still inside of our main div and you're gonna add a self-closing div this time with a class name of Fixed inset 0 and then you're gonna go ahead and add a linear gradient here so let's go ahead and add linear-gradient 180 degrees go ahead and pass in the first color which will be 0.0.0.8 like this after that a second color which will be rgba 0.0.0.4 which will be RGBA 0.0.0.4 and then the last RGBA 0.0.0.8 again like this and last one will be Z1 And let me zoom out so you can hopefully see this in one line. This is how the class name is supposed to be. And what's important is that there are no spaces inside of this curly brackets when you define background. So don't put space after a comma.
Don't put space anywhere. It needs to be all without spaces and then when you hover on it, you're going to see this complicated class name. So that's how you know that Tailwind has a working class name inside of it. And if you want to see colors the way I see colors, well for that, I think I have the color highlight installed. That's the extension.
And if you want to see the classes once you hover, I think we've already said that, but the extension for that is Tailwind CSS IntelliSense. Basically the first one that comes up. Great. So now if you save this, there we go. You have like a darkened image now in the radial, in linear gradient.
Great. So you can now sign up, you can now sign in and we have this beautiful login page. Amazing! So now that that is working, our next step is to actually add credential login. So one thing I want to just wrap up is this.
I want to go back inside of alph.vs and alongside sign in, I also want to redirect the error pages to sign in because we are going to display the error to the user ourselves. If you don't want that, you can also let NextOut handle it with their own page. Perhaps it could be more useful, but most of the time it just tells you something went wrong and that's something that we can handle as well if that's the amount of information it gives. Great, so Next step is enabling credential login. Great job!