Next.jsで使える認証ライブラリ、next-authでGoogle認証を試してみます。
公式を参考にしつつ動くところまでやってみます。永続化とかはしません。

ちなみに今回の内容はこのあたりに何もかも書いてあります。
https://next-auth.js.org/getting-started/example
https://next-auth.js.org/providers/google
https://developers.google.com/identity/protocols/oauth2

実装

next-auth導入

typescriptを導入したNext.jsのアプリを用意しておきます。
これをクローンする形でも問題ないです。

https://github.com/yubachiri/next-ts

npm i next-auth でnext-authをインストール。

そしたら実装を進めていきましょう。

認証情報の設定

まずはクライアントID・シークレットIDを用意します。

GCP > APIとサービス > 認証情報 より、「OAuthクライアントID」を作成してください。OAuth同意画面の設定を求められたらよしなに作成してください。

このへんが参考になると思います。
https://developers.google.com/identity/protocols/oauth2

今回はローカルで触ってみるところまでにするので、クライアントID作成時に設定することとなる 承認済みの JavaScript 生成元承認済みのリダイレクトURI はそれぞれ下記の内容にします。

生成元: http://localhost:3000
リダイレクトURI: http://localhost:3000/api/auth/callback/google

です。

gcp-setting

そしたらクライアントIDとクライアントシークレットをメモっておきます。

実装

適宜ファイルを作成したり編集したりしてください。

pages/api/auth/[...nextauth].ts

import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'

const options = {
  providers: [
    Providers.Google({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET
    })
  ],
}

export default (req, res) => NextAuth(req, res, options)

pages/_app.tsx

import { Provider } from 'next-auth/client'

export default function App ({ Component, pageProps }) {
  return (
    <Provider session={pageProps.session}>
      <Component {...pageProps} />
    </Provider>
  )
}

.env

GOOGLE_CLIENT_ID=メモった内容
GOOGLE_CLIENT_SECRET=メモった内容

ここまで書くと、認証処理が動くようになっています。動作確認できるようにしましょう。

pages/index.tsx

import React from 'react'
import { signIn, signOut, useSession } from 'next-auth/client'

export default function Page() {
  const [ session, loading ] = useSession()

  return <>
    {!session && <>
      Not signed in <br/>
      <button onClick={signIn}>Sign in</button>
    </>}
    {session && <>
      Signed in as {session.user.email} <br/>
      <button onClick={signOut}>Sign out</button>
    </>}
  </>
}

not-signed-in

sign-in

signed-in

これでGoogle認証が完了するところまでは実装が完了しました。お疲れ様です!以上です!

おまけ

だけだと味気ないので、ちょっとカスタマイズしてみます。

ログイン画面をいじってみましょうか。2ステップでいけます。

[...nextauth].tspages を追加

import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'

const options = {
  providers: [
    Providers.Google({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET
    })
  ],
  // 追加
  pages: {
    signIn: '/auth/signin'
  }
}

export default (req, res) => NextAuth(req, res, options)

pages/auth/signin.tsx を追加

import React from "react";
import { providers, signIn } from "next-auth/client";

export default function SignIn({ providers }) {
  return (
    <>
      <h2>ログイン</h2>
      {Object.values(providers).map((provider) => (
        <div key={provider.name}>
          <button onClick={() => signIn(provider.id)}>
            Sign in with {provider.name}
          </button>
        </div>
      ))}
    </>
  )
}

export async function getStaticProps(context) {
  return {
    props: {
      providers: await providers(context),
    },
  }
}

です。next-authがts対応してない?っぽい?のでところどころ警告出ますが…。

こんな画面になります。

login

ちなみにこの対応前に表示されていたものはnext-authが自動生成したものみたいですね。

NextAuth.js automatically creates simple, unbranded authentication pages for handling Sign in, Sign out, Email Verification and displaying error messages.

The options displayed on the sign up page are automatically generated based on the providers specified in the options passed to NextAuth.js.

https://next-auth.js.org/configuration/pages

とあります。

というわけで自由にログインページを編集できるようになりました。なお、この実装だとログイン後もこのページに留まるような形になります。気になる場合は手を入れてください。

以上

今回はこんなところです。とても少ないコードでログイン機能を実装できましたね。もちろんGoogle以外にも多くのプラットフォームをサポートしていたり、メール/パスワード認証やJWTにも対応しているみたいです。なんでも来いって感じですね。

今回は触れてませんがTypeORMやPrisma等を通してDB接続もいい感じに連携できるみたいです。