How to implement Google One Tap Sign-In with NextAuth in 2023
This tutorial is based on this really good, yet a bit outdated, blog post from Fabrizio Ruggeri.
I will go through the steps illustrated by Fabrizio, adding more contextual information about NextAuth and fixing a few out-of-date details. I personally struggled a lot to follow his tutorial and I so I set out to make a more beginner-friendly version of it.
What we’ll need:
- A custom CredentialsProvider
- An invisible parent component to host the One Tap UI
- A custom hook to implement the sign-in logic
prisma(i’m using prisma but you can use something else, the original example is with MongoDB)
What we’ll do:
We will create an invisible component, that hosts a custom hook. The custom hook, on render, uses NextAuth’s
useSession to see if there’s an active session. If there is no active session it shows the Google One Tap UI.
When the user clicks on the sign-in button the NextAuth
signIn function is called. This triggers a series of actions: checking if there is an existing session otherwise creating one, ditto for user and account (more info on this later).
This is pretty much it. Once the session is active NextAuth will be able to pick it up from anywhere in the client and the server with
Implementing a CustomCredentials Provider (backend)
The goal is to define what happens when a user tries to get authorized, in order to do this we need access to our database adapter, so in
[…nextauth].tsx we have to use the advanced initialization.
The most important things to understand here to keep the general thread are:
- We are creating a custom
Provider, with id ‘
Providercomes with a set of credentials that we define as a single field called
- When an attempt at signing in is made with this provider, the
authorizefunction is called and a
credentialmust be supplied. The
credentialbeing a token generated by the Google backend (more on this in a minute).
Client Side Implementation (frontend)
If you are using TypeScript, before continuing make sure you have installed
Importing the Google library on the client
To make the google library available on time and make sure that the Google One Tap UI renders correctly, you have to add the import in the
_document.tsx file. In fact, if you import it in
_app.tsx the library sometimes won’t be loaded in time and raise all types of annoying errors.
For this we use the Next.js
Script tag, as suggested by Fabrizio.
P.S. You may have seen this before implemented this way, placed in the document
<script src=”https://accounts.google.com/gsi/client" async defer></script>
I decided to go with the
Script tag solution because more elegant and because it took advantage of framework-specific features.
The Custom Hook
This is where a good chunk of the magic happens. The key element here is the
We’re going to use the second method. So that we don’t have to write the intialization code directly in the page but we can stow it away and then append the initialization logic to an html node/component of our choice.
Basically at every new page render, if there is no active session the Google One Tap UI will be rendered, and if the user clicks on it, the
signIn function is called, passing the user token to the NextAuth backend, calling our CredentialsProvider
authorize method and sending a request for the rest of the user’s info.
I got the idea for this imlementation from the NextAuth’s docs.
The invisible component
This component serves two purposes:
- calling the
useOneTapSigninhook and thus intializing the Google One Tap UI
- Defining it’s own position on the screen, which will correspond with the position where the Google One Tap UI will appear. In the example I’m using Tailwind CSS but whatever design system you’re using I recommend you to make it
stickyso that it doesn’t slide out of the viewport when users scroll down the page.
You should stick this component in your
Layout component if you have one, otherwise in some other element that is present in every page.