DEV Community

Peter Jacxsens
Peter Jacxsens

Posted on • Updated on

5/ NextAuth with GoogleProvider: sessions

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

And in our browser console, we see this:

{
  "user": {
    "name": "Peter Jacxsens",
    "email": "email",
    "image": "imagelink"
  },
  "expires": "2024-04-06T16:03:44.887Z"
}
Enter fullscreen mode Exit fullscreen mode

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.

signed in with nextauth googleprovider

signed out with nextauth googleprovider

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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 />
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 or geolocation
  • 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:

  1. Make a clear visual of the logged in state.
  2. To have easy access to the session by logging it out from these components.
  3. 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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

Add these components into the root layout and this is what we get: (obviously green when logged in)

logged in with nextauth googleprovider

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:

  1. We really need a custom sign in page. Also, what's with all of the reloads?
  2. 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.

Top comments (0)