This is the second part on the basic configuration of NextAuth
with GoogleProvider
. The finished code for this chapter is available on github (branch: basicgoogleprovider).
useSession in action
Let's add the useSession
hook to our <SingInButton />
since that is already a client component. We log the session:
'use client';
import { signIn, useSession } from 'next-auth/react';
export default function SignInButton() {
const { data: session, status, update } = useSession();
console.log('session', session);
return (
<button
className='bg-sky-400 rounded-md px-4 py-2'
onClick={() => signIn()}
>
sign in
</button>
);
}
And in our browser console, we see this:
{
"user": {
"name": "Peter Jacxsens",
"email": "email",
"image": "imagelink"
},
"expires": "2024-04-06T16:03:44.887Z"
}
Where does this come from? This is the default NextAuth
setup for GoogleProvider
. When we do our login process, some NextAuth
code had a chat with Google and got above user data. NextAuth
then put that in a JWT token
and wrote it into a cookie. useSession
reads the cookie, gets the JWT token
, extracts the data from it and returns it. And that is what we just logged into our browser.
Note that the session comes from our token in the cookie. NextAuth
does not go to Google every time to get this info.
getServerSession in action
What are we building here? When a user is not signed in, we want to display the sign in button. But when a user is signed in, we want to display the username and a sign out button.
First, go back to the <SignInButton />
and remove the useSession
hook and console.log
:
// frontend/src/app/components/header/SignInButton.tsx
'use client';
import { signIn } from 'next-auth/react';
export default function SignInButton() {
return (
<button
className='bg-sky-400 rounded-md px-4 py-2'
onClick={() => signIn()}
>
sign in
</button>
);
}
Duplicate this file, rename it to SignoutButton, import signOut
from NextAuth
:
// frontend/src/app/components/header/SignOutButton.tsx
'use client';
import { signOut } from 'next-auth/react';
export default function SignOutButton() {
return (
<button
className='bg-sky-400 rounded-md px-4 py-2'
onClick={() => signOut()}
>
sign out
</button>
);
}
This should be straightforward, we made a sign out button and NextAuth
provides us with a signOut
function.
Create a new component <NavbarUser />
. This will be an async server component that uses the getServerSession
function.
// frontend/src/app/components/header/NavbarUser.tsx
import { getServerSession } from 'next-auth';
import { authOptions } from '@/app/api/auth/[...nextauth]/authOptions';
import SignInButton from './SignInButton';
import SignOutButton from './SignOutButton';
export default async function NavbarUser() {
const session = await getServerSession(authOptions);
console.log('session', session);
if (!session) {
return <SignInButton />;
}
return (
<>
<div className='text-sky-700'>{session.user?.name}</div>
<SignOutButton />
</>
);
}
Again, simple. We call our getServerSession
function with the authOptions
object. We log session and then use it to show either a logged in or logged out UI.
Finally, in our <Navbar />
replace <SignInButton />
with <NavbarUser />
and let us take a look at session. As this is a server session, it will only log in the terminal, not in our browser:
getServerSession {
"user": {
"name": "Peter Jacxsens",
"email": "email",
"image": "imagelink"
}
}
We get the user object as before but not an expires date. There is a reason for this but we will not get into that in this series.
The auth flow
Testing time. We click sign out, the page does a full reload and then shows only the login button. Our terminal now shows:
getServerSession: null
We click the sign in button, page does a full reload to the default sign in page (the ugly one). We click sign in with Google button. This time google no longer asks us for permission but we are directly signed in and get redirect to our home page, again with a full page reload. Our terminal logs our user again.
And that's it. We have full sign in and out functionality and we know how to check if the user is logged in using the client component useSession
hook or the server side getServerSession
function.
Client or server components
At this time, you may be wondering when to use useSession
or getServerSession
and that is pretty simple. We use the same rational Next
uses. Always use server component except when you need a client component.
When do you need client components? When you need:
- Interactivity or event listeners (f.e. a button)
- Hooks
- Browser only api's like
localstorage
orgeolocation
- Class components
Expires
A NextAuth
session has a limited lifespan of 30 days. When the session expires, you will have to login again. The session lifespan can be set in the NextAuth
settings. Both NextAuth
and Strapi
recommend a max of 30 days for JWT tokens
.
Some extra components
We're going to do some cleanup. Firstly, remove the console.log
from our <NavbarUser />
component. Next, we are going to add 2 components, one with useSession
and one with getServerSession
.
We are going to use these 2 components to:
- Make a clear visual of the logged in state.
- To have easy access to the session by logging it out from these components.
- To handle some server and client component issues that we will face later on.
// frontend/src/components/loggedIn/LoggedInClient.tsx
'use client';
import { useSession } from 'next-auth/react';
export default function LoggedInClient() {
const { data: session } = useSession();
console.log('useSession', session);
return (
<div
className={`p-4 basis-2/4 rounded-sm text-center ${
session ? 'bg-green-400' : 'bg-red-400'
}`}
>
Client:{' '}
{session ? `logged in as ${session.user?.name}.` : 'not logged in.'}
</div>
);
}
and
// frontend/src/components/loggedIn/LoggedInServer.tsx
import { authOptions } from '@/app/api/auth/[...nextauth]/authOptions';
import { getServerSession } from 'next-auth';
export default async function LoggedInServer() {
const session = await getServerSession(authOptions);
console.log('getServerSession', session);
return (
<div
className={`p-4 basis-2/4 rounded-sm text-center ${
session ? 'bg-green-400' : 'bg-red-400'
}`}
>
Server:{' '}
{session ? `logged in as ${session.user?.name}.` : 'not logged in.'}
</div>
);
}
Add these components into the root layout
and this is what we get: (obviously green when logged in)
Summary
We configured GoogleProvider
in NextAuth
. We added a sign in button. This leads us to a default NextAuth
page that is not really usable in real live but does let us sign in with Google.
The useSession
hook and getServerSession
function let us verify if there is a user. When logged in, they return a user object with a name, email and image property. When logged out they return null. We use this info and change our UI accordingly.
But there are some issues:
- We really need a custom sign in page. Also, what's with all of the reloads?
- We haven't done any integration with
Strapi
. It has all been frontend. Currently no user will ever end up in our DB.
We will tackle these issues in the next chapters.
As a closure, I would like to mention that a lot of the information in this chapter came from this youtube video by Sakura Dev and this youtube video by Jack Herrington. But be careful, it is not 100% the same. So don't just drop snippets from one into the other! This goes for all tutorials. There is no one and only correct way to use Nextauth
.
If you want to support my writing, you can donate with paypal.