## Why authenticate with Google?

Many users own or use Google products, making it practical to use Google for
Single Sign-On (SSO) and authentication. SSO provides access to valuable
metadata that we can use for personalization in collaborative workspaces.
Additionally, implementing Single Sign-On improves security by allowing users to
bypass entering their password repeatedly.

## Using NextAuth.js to add Google authentication to our Next.js application

Because we build the majority of our Liveblocks examples with Next.js (including
the [Starter Kit](/nextjs-starter-kit)), we recommend using Next.js providers
for authentication. If you don’t want to use
[NextAuth.js](https://next-auth.js.org/), you can use the
[Google Platform Library](https://developers.google.com/identity/sign-in/web/sign-in)
for Google Single Sign On. Authentication providers and the client library are
the only officially supported ways to include Google SSO as of March 2023.

## Updating an existing Next.js + Liveblocks app

We will be updating the
[Live Avatar Example](/examples/live-avatar-stack/nextjs) to include Google
authentication. The Live Avatar Example is a Next.js application that uses
Liveblocks to create a collaborative avatar stack. The application is a great
starting point for adding authentication because it is a simple application that
uses Liveblocks to create a collaborative experience. These are the steps we
will take to add Google authentication to the Live Avatar Example:

- [Obtaining Google credentials](#Obtaining-Google-credentials)
- [Using Credentials in Liveblocks app](#Using-Credentials-in-Liveblocks-app)
- [Updating the NextAuth.js configuration](#Updating-the-NextAuth.js-configuration)
- [Using NextAuth.js to expose the session object across the app](#Using-NextAuth.js-to-expose-the-session-object-across-the-app)
- [Updating the Liveblocks demo authentication with values from NextAuth.js](#Updating-the-Liveblocks-demo-authentication-with-values-from-NextAuth.js)
- [Create redirect functionality when a user is not signed in](#Create-redirect-functionality-when-a-user-is-not-signed-in)
- [Update the referrer policy on the Avatar image for local development](#Update-the-referrer-policy-on-the-Avatar-image-for-local-development)
- [Create the Google SVG icon](#Create-the-Google-SVG-icon)
- [Create the sign-in page](#Create-the-sign-in-page)

### Obtaining Google credentials

NextAuth.js has the concept of `Providers`: services such as GitHub, Google,
etc. utilizing OAuth, which allows you to log in to your application using
existing credentials.

Similar to our [Starter Kit guide](/docs/tools/nextjs-starter-kit) in which we
detail how to get authentication credentials for GitHub and Auth0, we will
create Google credentials to enable Google as a provider.

1. First, navigate to [Google Console](https://console.cloud.google.com/). If
   you do not already have an account setup, you need to create a Google account
   and an associated project which is where you will generate credentials from.

   <Figure>
     <video autoPlay loop muted playsInline>
       <source
         src="/images/blog/google-sso/create-google-project.mp4"
         type="video/mp4"
       />
     </video>
   </Figure>

2. Once you have created the new project, navigate to APIs and Services. From
   the lefthand navigation, select Credentials and then `+ CREATE CREDENTIALS`
   from the top portion of the page. Select "CONFIGURE CONSENT SCREEN."

3. Set the "User Type" as External, and then Save. On the page that opens, fill
   out your application information, setting your application domain to
   `http://localhost:3000` (or your production domain). Once you have filled out
   the information, click Save.

4. The next page that will open is Scopes. Here, you can update the scopes to
   access different information from a user's account. For more information, you
   can review the
   [Google documentation](https://developers.google.com/identity/protocols/oauth2/scopes?authuser=1).
   For this example, we will use `userinfo.email` and `userinfo.profile` (these
   pieces include the profile image, email, and name).
5. On the Test Users screen, you can add the Google accounts of people you will
   allow to access your app. If you do not add a user to your list, they can
   still log in with Google; however, their profile image will be empty.

   <Figure>
     <video autoPlay loop muted playsInline>
       <source
         src="/images/blog/google-sso/oauth-screen.mp4"
         type="video/mp4"
       />
     </video>
   </Figure>

6. Navigate back to Credentials and select `+ CREATE CREDENTIALS` and select
   OAuth client ID. On the next page, select Web application as the Application
   type.

7. Name your client, and update Authorized JavaScript origin to
   `http://localhost:3000` and Authorized redirect URIs to
   `http://localhost:3000/api/auth/callback/google`. Note that we use
   `localhost:3000` for local development, but you will want to update this
   portion of the URI when your app is in production. At this point, you will
   want to save your `CLIENT_ID` and `CLIENT_SECRET`. The `CLIENT_SECRET` will
   not be revealed again; if you lose the value, you will have to regenerate it.

   <Figure>
     <video autoPlay loop muted playsInline>
       <source
         src="/images/blog/google-sso/oauth-settings.mp4"
         type="video/mp4"
       />
     </video>
   </Figure>

### Using Credentials in Liveblocks app

Now that we have the credentials for Google, we can bring them into our
Liveblocks application and use this information to set up our NextAuth.js
provider and populate our avatar profiles.

For this example, we will use the
[Live Avatar Stack](/examples/live-avatar-stack/nextjs) as the baseline for
implementing authentication. After cloning the Liveblocks repo, you should
navigate to the Live Avatar example like so:

```

npx create-liveblocks-app@latest --example nextjs-live-avatars --api-key --install

```

First run `npm install next-auth`, `npm install @svgr/webpack --save-dev`, and
finally, `npm install` from this directory level to install all package
dependencies necessary for this example.

Generate two encrypted tokens for your Next.js app: a `JWT_SECRET` and a
`NEXTAUTH_SECRET`. The `JWT_SECRET` is used for local development with Next.js,
while the `NEXTAUTH_SECRET` is used in production.

To generate these values, we can run the following command:
`openssl rand -base64 32` and copy the output of each for adding to your
`env.local` file.

In your `env.local` file, add the following values, and populate them:

```bash
LIVEBLOCKS_SECRET_KEY="<your secret from the dashboard>"
GOOGLE_CLIENT_ID="<your client id from the google console>"
GOOGLE_CLIENT_SECRET="<your client secret from the google console>"
NEXTAUTH_SECRET="<your NextAuth.js secret generated in the console in the previous step>"
NEXTAUTH_URL="http://localhost:3000"
JWT_SECRET="<your JWT secret generated in the console in the preivious step>"
```

### Updating the NextAuth.js configuration

Next we will create the `next-auth-d.ts` file which will expose the
`SessionType` to submodules across our app:

```ts file="next-auth-d.ts"
import { User } from "../types";
import NextAuth from "next-auth";

declare module "next-auth" {
  /**
   * Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
   */
  interface Session {
    user: User;
  }
}
```

The User type defined above is not defined by default, so we should add its
definition to a new `types.ts` file at the root directory level.

```ts file="types.ts"
export type User = {
  name: string;
  email: string;
  image: string;
};
```

We will now add the Google Provider to `pages/api/auth/[...nextauth].ts`. This
file configures the authorization to Google, which will be called when we
implement sign-in and sign-out functionality further on in this tutorial.

```ts file="[...nextauth].ts"
import { authorize } from "@liveblocks/node";
import { NextApiRequest, NextApiResponse } from "next";
import NextAuth from "next-auth";
import { Session } from "next-auth";
import GoogleProvider from "next-auth/providers/google";

export const authOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
      authorization: {
        params: {
          prompt: "consent",
          access_type: "offline",
          response_type: "code",
        },
      },
    }),
  ],
  secret: process.env.JWT_SECRET,
};

export default NextAuth(authOptions);
```

### Using NextAuth.js to expose the session object across the app

Now that we have updated our authentication provider and ensured the types
defined from NextAuth.js are accessible, we will wrap our app in the
`SessionProvider`. Wrapping our application with the `SessionProvider` makes the
session object that NextAuth.js generates available across the various
components of your app. In our case, the session object would include your
Google email, name, and profile image.

Update `pages/_app.tsx` to look like the following:

```ts file="_app.tsx" highlight="3,4,27,29"
import { AppProps } from "next/app";
import Head from "next/head";
import { Session } from "next-auth";
import { SessionProvider } from "next-auth/react";
import "../styles/globals.css";

function App({ Component, pageProps }: AppProps<{ session: Session }>) {
  return (
    <>
      <SessionProvider session={pageProps.session}>
        <Component {...pageProps} />
      </SessionProvider>
    </>
  );
}
export default App;
```

### Updating the Liveblocks demo authentication with values from NextAuth.js

At this point, we still have a few wiring pieces to hook up, namely,
authentication from Liveblocks where we will use the information provided by
Google to update our Liveblocks users, which will populate our Avatars.

We will be updating the file `pages/api/auth.ts` to do so.

First, we will create a utility function to import into our auth file. If you’re
familiar with the Starter Kit, you may have realized that this function is also
used there.

Create the following file in the `pages/api/auth` directory:

```ts file="getServerSession.ts"
import type { GetServerSidePropsContext } from "next";
import { unstable_getServerSession } from "next-auth/next";
import { authOptions } from "../../../pages/api/auth/[...nextauth]";

export function getServerSession(
  req: GetServerSidePropsContext["req"],
  res: GetServerSidePropsContext["res"]
) {
  return unstable_getServerSession(req, res, authOptions);
}
```

Now in `pages/auth/auth.ts`, update the auth function to use the session and to
pass that information to Liveblocks. We’re removing the random names and instead
using the profile data from Google.

Your `auth.ts` file should look like the following:

```ts file="auth.ts" highlight="2,3,4,12,14-19,28-31"
import { authorize } from "@liveblocks/node";
import { NextApiRequest, NextApiResponse } from "next";
import { getServerSession } from "./auth/getServerSession";
import { User } from "../../types";

const API_KEY = process.env.LIVEBLOCKS_SECRET_KEY;

export default async function auth(req: NextApiRequest, res: NextApiResponse) {
  if (!API_KEY) {
    return res.status(403).end();
  }
  const session = await getServerSession(req, res);

  const anonymousUser: User = {
    name: "Anonymous",
    email: "none",
    image: "N/A",
  };
  const { name, email, image } = session?.user ?? anonymousUser;

  // We're generating users and avatars here based off Google SSO metadata.
  //This is where you assign the
  // user based on their real identity from your auth provider.
  // See https://liveblocks.io/docs/api-reference/liveblocks-node#authorize for more information
  const response = await authorize({
    room: req.body.room,
    secret: API_KEY,
    userId: `user-${email}`,
    userInfo: {
      name: name,
      picture: image,
    },
  });
  return res.status(response.status).end(response.body);
}
```

### Create redirect functionality when a user is not signed in

Now that we have established connections between Liveblocks and Google, we need
to bring sign-in and redirect functionality into our room. First, we will set up
a redirect that checks for a user’s session before allowing them into a
Liveblocks room, and then we will create a sign-in page.

Update `pages/index.tsx` to `getServerSideProps` and enable redirect.

```tsx file="index.tsx" highlight="3,5,7,8,42-43,77-102"
import React, { useMemo } from "react";
import { Avatar } from "../components/Avatar";
import Button from "../components/Button";
import { RoomProvider, useOthers, useSelf } from "../liveblocks.config";
import { GetServerSideProps } from "next";
import { useRouter } from "next/router";
import { getServerSession } from "./api/auth/getServerSession";
import { signOut } from "next-auth/react";
import styles from "./index.module.css";

function Example() {
  const users = useOthers();
  const currentUser = useSelf();
  const hasMoreUsers = users.length > 3;

  return (
    <div className="flex h-screen flex-col place-content-center place-items-center space-y-5">
      <div className="flex w-full place-content-center place-items-center select-none">
        <div className="flex pl-3">
          {users.slice(0, 3).map(({ connectionId, info }) => {
            return (
              <Avatar
                key={connectionId}
                picture={info.picture}
                name={info.name}
              />
            );
          })}

          {hasMoreUsers && (
            <div className={styles.more}>+{users.length - 3}</div>
          )}

          {currentUser && (
            <div className="relative ml-8 first:ml-0">
              <Avatar picture={currentUser.info.picture} name="You" />
            </div>
          )}
        </div>
      </div>
      <div>
        <Button onClick={() => signOut()}>Sign Out</Button>
      </div>
    </div>
  );
}

export default function Page() {
  const roomId = useOverrideRoomId("nextjs-live-avatars");

  return (
    <RoomProvider id={roomId} initialPresence={{}}>
      <Example />
    </RoomProvider>
  );
}

export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
  const session = await getServerSession(req, res);

  if (!session) {
    return {
      redirect: {
        permanent: false,
        destination: "/signin",
      },
    };
  }

  return {
    props: {},
  };
};
```

### Update the referrer policy on the Avatar image for local development

When running the app locally, you may notice that the avatar images are not
loading. This is because the referrer policy is set to
`strict-origin-when-cross-origin` by default. To fix this, update the referrer
policy on the `Avatar` component to `no-referrer` in `components/Avatar.tsx`:

```tsx file="components/Avatar.tsx" highlight="14"
import React from "react";
import styles from "./Avatar.module.css";

const IMAGE_SIZE = 48;

export function Avatar({ picture, name }) {
  return (
    <div className={styles.avatar} data-tooltip={name}>
      <img
        src={picture}
        height={IMAGE_SIZE}
        width={IMAGE_SIZE}
        className={styles.avatar_picture}
        referrerPolicy="no-referrer"
      />
    </div>
  );
}
```

### Create the Google SVG icon

Before creating the sign-in page, we will add the Google SVG and configure our
local environment to use it.

Create a new folder called `public` in the project's root, and inside it, create
a folder called `icons`. Inside the `icons` folder, create a file called
`google.svg` and copy the following code into it:

```svg file="public/icons/google.svg"
<svg aria-hidden="true" focusable="false" width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M17.64 9.204c0-.638-.057-1.251-.164-1.84H9v3.48h4.844a4.14 4.14 0 0 1-1.796 2.717v2.258h2.908c1.702-1.566 2.684-3.874 2.684-6.615Z" fill="#4285F4"/><path fill-rule="evenodd" clip-rule="evenodd" d="M9 18c2.43 0 4.467-.806 5.956-2.18l-2.909-2.259c-.805.54-1.836.86-3.047.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18Z" fill="#34A853"/><path fill-rule="evenodd" clip-rule="evenodd" d="M3.964 10.71A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.957 4.042l3.007-2.332Z" fill="#FBBC05"/><path fill-rule="evenodd" clip-rule="evenodd" d="M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.462.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.958L3.964 7.29C4.672 5.163 6.656 3.58 9 3.58Z" fill="#EA4335"/></svg>
```

Create the `next.config.js` file, which handles the advanced configuration for
loading SVGs during local development:

```js file="next.config.js"
module.exports = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/,
      use: ["@svgr/webpack"],
    });

    return config;
  },
};
```

### Create the sign-in page

Now we need to create a sign-in page. Users will be redirected to the sign-in
page if they are not logged in. We will use the `next-auth/react` package to
handle the authentication.

Create the `signin` page:

```tsx file="pages/signin.tsx"
import styles from "../components/SignIn.module.css";

import { GetServerSideProps } from "next";
import { getProviders } from "next-auth/react";
import { useSession, signIn } from "next-auth/react";
import { getServerSession } from "./api/auth/getServerSession";
import Button from "../components/Button";
import GoogleIcon from "../public/icons/google.svg";

interface Props {
  providers: Awaited<ReturnType<typeof getProviders>>;
}

export default function login({ providers }: Props) {
  const { data: session } = useSession();
  if (!session)
    return (
      <div className={styles.signin}>
        <Button
          className={styles.googlebutton}
          onClick={() => signIn("google")}
        >
          <GoogleIcon />
          Sign in with Google
        </Button>
      </div>
    );
}

// If not logged in redirect to signin
export const getServerSideProps: GetServerSideProps = async ({ req, res }) => {
  const session = await getServerSession(req, res);
  const providers = await getProviders();
  console.log(providers);

  if (session) {
    return {
      redirect: {
        permanent: false,
        destination: "/",
      },
    };
  }

  return {
    props: { providers },
  };
};
```

Create the `SignIn` css module:

```css file="styles/SignIn.module.css"
.signin {
  position: absolute;
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  place-content: center;
  place-items: center;
  background-color: rgb(var(--color-surface));
}

.googlebutton {
  user-select: none;
  gap: 0.5rem;
}
```

We have completed the process of styling and adding the sign-in and sign out
functionality to the app. Now that we have completed these steps, we can run the
app and see our changes.

```
npm run dev
```

Open the console to `localhost:3000`, and you will see the sign-in screen.

<Figure>
  <video width={672} height={448} autoPlay loop muted playsInline>
    <source
      src="/images/blog/google-sso/sign-in-with-google-live-avatars.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

We hope that this tutorial gives you the tools to populate avatars in a way that
enhances your collaborative experience while improving your understanding of how
authentication can work with NextAuth.js providers. Additionally, the
[Starter Kit](/starter-kit) is pre-configured with NextAuth.js, which means you
can follow this tutorial to integrate personal data from Google into the
preconfigured avatars. If you want to checkout the source code for this example,
you can view it on
[GitHub](https://github.com/liveblocks/liveblocks/tree/main/examples/nextjs-nextauth-google-avatars).
If you have any feedback or suggestions for future updates, please don’t
hesitate to reach out to us via [email](mailto:support@liveblocks.io),
[Twitter](https://twitter.com/liveblocks), or in our
[Discord community](/discord).