In this chapter we're going to installNextAuth
and setup a basic example with Google provider. Note that ourNext
app only has a single page, the home page (/app/index
) and a single component<Navbar />
that has one link to the home page. The finished code for this chapter is available ongithub (branch: basicgoogleprovider).
Install
InstallNextAuth
in thefrontend folder:
npm i next-auth
Next, we setup a route handler forNextAuth
. We create aroute.ts
file in a new foldersrc/app/api/auth/[...nextauth]/route.ts
. The[...nextauth]
folder is a catch all route inNext
. This means that all requests toapi/auth
or to for exampleapi/auth/local/register
will be handled by our newly createdroute.ts
route handler. Put this inside the handler:
// frontend/src/app/api/auth/[...nextauth]/route.tsimportNextAuthfrom'next-auth';import{authOptions}from'./authOptions';consthandler=NextAuth(authOptions);export{handlerasGET,handlerasPOST};
Create theauthOptions.ts
file that gets referred to above.
Note here:authOptions
is just an object with configuration and customizations properties. Most tutorials just write it as an object literal in the route handler. However, when runningNext build
it gave me a TypeScript error at a certain point. One of theNextAuth
authors suggested to place theauthOptions
in a separate file. This did solved the problem and that is why we are puttingauthOptions
in a separate file.
// frontend/src/app/api/auth/[...nextauth]/authOptions.tsimport{NextAuthOptions}from'next-auth';importGoogleProviderfrom'next-auth/providers/google';exportconstauthOptions:NextAuthOptions={providers:[GoogleProvider({clientId:process.env.GOOGLE_CLIENT_ID??'',clientSecret:process.env.GOOGLE_CLIENT_SECRET??'',}),],};
What happens here: we add our first provider to the providers list. We then configureGoogleProvider
that we import fromNextAuth
. The client id and secret come from the.env
file that we wrote inchapter 1.
By the way, to read theNextAuth
docs on this, just googleNextAuth provider google
and that will lead you to thedocs page where you will see this setup.
Finally, add following lines to your .env.local file: (This isn't strictly required in development but will prompt warnings in your terminal.)
# frontend/.env.localNEXTAUTH_URL=http://localhost:3000NEXTAUTH_SECRET=EDITME->somesecret
WhereNEXTAUTH_SECRET
is a secret you need to generate. For windows user, open bash and enter following:
openssl rand -base64 32
Copy the return string and paste it into your.env.local
file. Other platforms I'm not sure, look it up.
Our first login with GoogleProvider in NextAuth
We are now ready for our first login. Yes, it is that easy. We create a login button:
// src/components/header/SignInButton.tsx'use client';import{signIn}from'next-auth/react';exportdefaultfunctionSignInButton(){return(<buttontype='button'className='bg-sky-400 rounded-md px-4 py-2'onClick={()=>signIn()}> sign in</button>);}
Firstly, we make it a client component because our button needs an event handler. In the onClick event we passsignIn
. This is a function fromNextAuth
that when called will start the sign in procedure.
We only have our homepage right now but that is ok. In our currentNextAuth
configuration there is no custom login page andNextAuth
will redirect us to aNextAuth
default login page. We will customize this later with our own page. Let's run ourNext
frontend and click the sign in button. We are redirected tohttp://localhost:3000/api/auth/signin?callbackUrl=http%3A%2F%2Flocalhost%3A3000%2F
(with callback parameter to home page):
This is the default login pageNextAuth
provides and there are some things we need to say about this:
- Obviously, it not a nice design.
- You cannot change this page with f.e. other styling.
- If you're not coding along you won't know this but clicking the login button triggered a full page reload (F5 reload).
Conclusion, this is not something you would want to use in production but here, it does serve some purpose. Let's click theSign in with Google link and see what happens:
- We are redirected to
https://accounts.google.com/o/oauth2/v2/auth/...
(only on first login) - We are asked what google account we want to use. (only on first login)
- We are asked if we want to login to -appname- and that means that Google will share following data -some data-. (only on first login) (These align with the settings we made inchapter 1, Google OAuth setup)
- On clicking continue we are redirected to our frontend homepage
localhost:3000
.
If we logout and login again (which we can't yet), the first 3 steps will be skipped. This is just the classic authentication flow with Google as I'm sure we've all done.
But, it works, so yay! What we're missing is feedback. Are we logged in or not? We are but we don't know and that is our next step.
NextAuth Session
We are now signed in usingNextAuth
. Practically, that means thatNextAuth
verified us with Google and then set some cookies, one with aJWT token
. But, we don't have to worry about cookies.
NextAuth
provides us with 2 ways to verify if a user is logged in:
- For client components: the
useSession
hook. - For server components: the
getServerSession
function.
NextAuth useSession hook
useSession
is a hook, so you can only use it in client components. It's just a hook, so you call it (no parameter required) and it returns an object that you destructure.
'use client';import{useSession}from'next-auth/react';const{data:session,status,update}=useSession();
For now we ignore status and update and focus on the data property that we rename to session. Our session will be either null/undefined (not logged in) or an object of type DefaultSession:
{user?:{name?:string|nullemail?:string|nullimage?:string|null}expires?:string}
This session interface can and will be customized, meaning we put more data on it.
NextAuth getServerSession() function
getServerSession
is an async function that you use in server components or route handlers.
- It takes one parameter, the
authOptions
object that we pass in ourapp/api/auth/[...nextAuth]/route.ts
route handler. - It returns either null (not logged in) or the default session from just above.
- Notice the async and await keywords!
import{getServerSession}from'next-auth';import{authOptions}from'@/app/api/auth/[...nextauth]/authOptions';exportdefaultasyncfunctionMyComponent(){constsession=awaitgetServerSession(authOptions);// ...}
Let's add this to our code to get a better feel for it. Firstly though, to runuseSession
, we have to wrap our entire app into a provider thatNextAuth
gives us.
NextAuth SessionProvider
Things get a bit complicated here but in the end it is just a configuration so don't worry about it too much.
The problem is that theSessionProvider
thatNextAuth
gives us is a client component because it usesReact
hooks. But, sinceNextAuth v4
is getting a bit older, it doesn't use theuse client
directive. This makesNext
throw an error.
You can read more about this problem and how to solve it in theNext docs. The solution is to importSessionProvider
in a client component and immediately export it like this:
// frontend/src/app/component/Provider.tsx'use client';import{SessionProvider}from'next-auth/react';exportdefaultSessionProvider;
We now can use this<Provider />
component to wrap around our app inside our root layout file:
// frontend/src/app/layout.tsx//...importNavBarfrom'@/components/header/Navbar';import{SessionProvider}from'next-auth/react';import{getServerSession}from'next-auth';import{authOptions}from'./api/auth/[...nextauth]/authOptions';//...exportdefaultasyncfunctionRootLayout({children,}:Readonly<{children:React.ReactNode;}>){constsession=awaitgetServerSession(authOptions);return(<htmllang='en'><bodyclassName={`${inter.className} px-2 bg-zinc-200`}><SessionProvidersession={session}><divclassName='max-w-6xl mx-auto'><NavBar/><mainclassName='my-4'>{children}</main></div></SessionProvider></body></html>);}
Note how we made RootLayout async but again, don't worry to much about this, in the end it is just configuration. We continue in the next chapter.
If you want to support my writing, you candonate with paypal.
Top comments(1)
For further actions, you may consider blocking this person and/orreporting abuse