Next.jsとSupabase Ui Libraryで作るGoogleアカウント認証サイト

# はじめに

こんにちは。elephantnodeと申します。

普段は都内で社内情シス+Web系エンジニアとして業務しています。

新たに**Googleアカウント認証機能付き**の**Next.js**のアプリ開発を始めようと思い、準備していたところ、**Supabase UI Library**に**Social Auth**が追加されていたので、試してみました。

https://supabase.com/ui

**Supabase UI Library**は**shadcn/ui**をベースとした**Reactのコンポーネントライブラリ**です。

単純な**Tailwind**のテンプレートではなく、様々な機能を持ち合わせたライブラリのため、追加されるファイル数も多く、既存のプロジェクトに組み込むにはかなりの慎重さが要求されます。

そのため、まずはシンプルに検証環境を、なるべく早く作成できるようになっていると良いと思いましたので、今後の開発のために記事へまとめてみました。

## この記事はNext.jsのセットアップとSupabase、Vercelの連携を前提にしています

さっそく進めて行きたいと思いますが、この記事は前回の**Next.js+Supabase+Vercelのセットアップについて**を前提にしています。

https://qiita.com/murodon/items/b5d4fb4ff2aec2313456

**Next.js**をセットアップしてSupabaseの環境変数を作成する方法や、**SupabaseとVercelを連携する方法**は前回の記事をご参照ください。

## SupabaseでGoogleをAuthプロバイダーに設定する

まずは**Google Cloud**に新しいプロジェクトを作成します。

![新しいプロジェクト_–_ダッシュボード_–_elephantnode_com_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/790d81ac-4898-4a73-9799-8b4ad6e7a5dc.png)

プロジェクトに移動して、APIとサービス>OAuth同意画面に進みます。

![Cursor_と_ダッシュボード_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/3e59ca45-5e1d-40f4-8f84-5541b101a72d.png)

![OAuth_の概要_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/700af367-7ba7-45e7-9eb5-a995d0803291.png)

OAuth同意画面は、`Google Auth Platform`という名称のようです。開始ボタンで設定を進めます。

![プロジェクト構成_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/4c8d4704-ad3e-40d4-b1b9-261ece9b357f.png)

アプリの名称を入力。サポート用のメールアドレスを入力。

次に認証するユーザーの対象を選択します。内部だと、Google Workspaceのメンバーのみが利用できるようになりますが、今回は外部で設定していきます。


![プロジェクト構成_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール_と_Google_Chat_-_Chat.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/e822e89d-5c38-40c2-82cf-a2add7807d7f.png)



![プロジェクト構成_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール_と_Next_js___supabase___vercelでGoogle認証付きサイトを作ってみる.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/4e60c47a-e50a-4b64-adc3-eaba604f0290.png)

連絡先情報に、Googleからのお知らせを受信するためのメールアドレスを入力します。

![プロジェクト構成_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール_と_Next_js___supabase___vercelでGoogle認証付きサイトを作ってみる.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/9e56665f-fcb4-4fbc-a738-27637d8d5c36.png)

規約への同意にチェックして作成をクリックします。

## OAuthクライアントIDの作成

![OAuth_の概要_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/447490f4-2fd9-4bd2-b0db-1fc224bb2074.png)

最初のみOAuthの概要ページに移動します。（もしくはAPIとサービス>OAuth同意画面からも入れますし、API>サービスの認証情報からも作成画面に入れます。）

![OAuth_クライアント_ID_の作成_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/45ce50f2-5273-47e8-8c42-611de30d326b.png)

アプリケーションの種類に`ウェブアプリケーション`をプルダウンで選択します。

![OAuth_クライアント_ID_の作成_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/d56d06a2-b8b4-4698-860b-4235d8244389.png)

画面が変わっていろいろと出てきますが、後ほど設定するので、クライアントIDの名前だけ入力して、作成します。

![OAuth_クライアント_ID_の作成_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/7e4c8630-5fb9-4348-b143-8c2f8450890b.png)

クライアントIDとシークレットの情報が表示されます。コピーしておくか、JSONをダウンロードしておきましょう。

## SupabaseでAuthenticationを設定

Supabaseの`Authentication`>`Sign In / Providers`を開き、`Auth Providers`から`Google`をクリックします。


![Cursor_と_Authentication___Supabase.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/b6c45372-e6da-4294-b24a-58683933b125.png)

![Authentication___Supabase.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/c2c178b2-8f24-47d5-ae18-9d385209f14b.png)


設定画面を開き、`Enable Sign in wite Google`のトグルをオンに設定し、GCPのOAuthクライアントIDで取得した**クライアントID**と**シークレット**を入力してSave。

![Authentication___Supabase_と_Next_js___supabase___vercelでGoogle認証付きサイトを作ってみる.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/ae3d667b-1fab-479e-9fd5-13bc3ec48863.png)


再度、`Auth Providers`から`Google`を開き、`Callback URL(for OAuth)`のボタンでクリップボードへCopyして、Callback URLを取得します。

![Cursor_と_認証情報_–_API_とサービス_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/c47d1d32-903a-46d4-a0ce-d73e9cc0a838.png)

GCPの`APIとサービス`＞`認証情報`で、先程作成したOAuth2.0クライアントIDの設定を開く。

![Cursor_と_ウェブ_アプリケーション_のクライアント_ID_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール_と_Vue3とSupabaseで作るGoogleアカウント認証サイト__Vue_js_-_Qiita_🔊_と_Next_js___supabase___vercelでGoogle認証付きサイトを作ってみる.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/7c90ee04-b29d-4344-8938-886cce3f79fa.png)

承認済みのリダイレクトURIのフォームに、先程取得した**Supbase**の`Callback URL(for OAuth)`を入力して保存します。

## データアクセスを設定

OAuth経由でGoogleのアカウントから取得できる情報の範囲を設定しておきます。

https://supabase.com/docs/guides/auth/social-login/auth-google?queryGroups=platform&platform=web

データアクセスで必要なスコープは下記の3つです。

.../auth/userinfo.email
...auth/userinfo.profile
openid

Google Auth Platformの設定画面で、データアクセスを開きます。

![データアクセス_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/b8f2ab85-a82a-47eb-a625-70cff73e7ac2.png)

スコープを追加または削除をクリックすると、設定が開きます。

![Cursor_と_データアクセス_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/9cc17881-90af-40ef-990b-7756950f602e.png)


メールアドレスの参照、ユーザーの個人情報の表示、openidのチェックボックスを選択します。下側に更新ボタンがありますのでクリック。

![Cursor_と_データアクセス_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/ab687f8e-4de4-4fc6-aa68-3b29018c9761.png)

最後、忘れずにSaveしましょう。

## Next.jsでSupabase UI Libraryを使ってログイン画面を作成

前回作成した**Supbase+Vercel+Next.jsの連携済みアプリ**にライブラリを追加します。

念の為にですが、下記の内容がローカルに設定済みです。

* **Next.js**のローカルセットアップ
* **Supabase**と**Vercel**の連携が設定済み
* **Supabase**の環境変数を**Next.js**の`.env.local`に取得済み

https://qiita.com/murodon/items/b5d4fb4ff2aec2313456

まずは**Supabase**のパッケージをインストールします。

https://supabase.com/docs/guides/auth/server-side/nextjs?queryGroups=router&router=app


```
npm install @supabase/supabase-js @supabase/ssr
```

次に、**Supabase UI Library**から`Social Authentication`をインストールします。

https://supabase.com/ui/docs/nextjs/social-auth

```bash
❯ npx shadcn@latest add https://supabase.com/ui/r/social-auth-nextjs.json

? You need to create a components.json file to add components. Proceed? › (Y/n)
? Which color would you like to use as the base color? › - Use arrow-keys. Return to submit.
❯   Neutral
    Gray
    Zinc
    Stone
    Slate
✔ Writing components.json.
✔ Checking registry.
  Installing dependencies.

It looks like you are using React 19. 
Some packages may fail to install due to peer dependency issues in npm (see https://ui.shadcn.com/react-19).

? How would you like to proceed? › - Use arrow-keys. Return to submit.
❯   Use --force
    Use --legacy-peer-deps

Use --force
✔ Installing dependencies.
✔ Created 12 files:
  - src/app/auth/login/page.tsx
  - src/app/auth/error/page.tsx
  - src/app/protected/page.tsx
  - src/app/auth/oauth/route.ts
  - src/components/login-form.tsx
  - src/middleware.ts
  - src/components/logout-button.tsx
  - src/lib/supabase/client.ts
  - src/lib/supabase/middleware.ts
  - src/lib/supabase/server.ts
  - src/components/ui/button.tsx
  - src/components/ui/card.tsx
```

インストール中に設定が必要な項目は3つです。

1つ目はインストールの確認、2つ目はベースカラーの選択です。

最後は**Next.js**のlatestが現時点では**Next.js15+React 19環境**なので、**Supabase UI Library**で採用しているコンポーネントライブラリのshadcn/uiがそのままインストールしようとするとパッケージの依存関係でエラーが発生するため、強制的にインストールするためのコマンドを選ぶ必要があるとのことです。

すべてに答えるとインストールは完了しました。

**Next.js**のアプリを確認すると、すっからかんだったsrcフォルダに、様々なファイルが増えていることを確認できます。

以下srcの構成内容です。

```bash
❯ tree -a     
.
├── app
│   ├── auth
│   │   ├── error
│   │   │   └── page.tsx
│   │   ├── login
│   │   │   └── page.tsx
│   │   └── oauth
│   │       └── route.ts
│   ├── favicon.ico
│   ├── globals.css
│   ├── layout.tsx
│   ├── page.tsx
│   └── protected
│       └── page.tsx
├── components
│   ├── login-form.tsx
│   ├── logout-button.tsx
│   └── ui
│       ├── button.tsx
│       └── card.tsx
├── lib
│   ├── supabase
│   │   ├── client.ts
│   │   ├── middleware.ts
│   │   └── server.ts
│   └── utils.ts
└── middleware.ts

10 directories, 17 files
```

## OAuthログインプロバイダーを変更する

さきほどログインに必要なコンポーネントが一式インストールされましたが、**Supabase Ui Library**の`Social Authentication`はデフォルトで`Github`が認証プロバイダーに設定されています。このProviderを`google` に変更します。

```src/components/login-form.tsx```を編集します。

```src/components/login-form.tsx
'use client'

import { cn } from '@/lib/utils'
import { createClient } from '@/lib/supabase/client'
import { Button } from '@/components/ui/button'
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from '@/components/ui/card'
import { useState } from 'react'

export function LoginForm({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {
  const [error, setError] = useState<string | null>(null)
  const [isLoading, setIsLoading] = useState(false)

  const handleSocialLogin = async (e: React.FormEvent) => {
    e.preventDefault()
    const supabase = createClient()
    setIsLoading(true)
    setError(null)

    try {
      const { error } = await supabase.auth.signInWithOAuth({
        provider: 'github',
        options: {
          redirectTo: `${window.location.origin}/auth/oauth?next=/protected`,
        },
      })

      if (error) throw error
    } catch (error: unknown) {
      setError(error instanceof Error ? error.message : 'An error occurred')
      setIsLoading(false)
    }
  }

  return (
    <div className={cn('flex flex-col gap-6', className)} {...props}>
      <Card>
        <CardHeader>
          <CardTitle className="text-2xl">Welcome!</CardTitle>
          <CardDescription>Sign in to your account to continue</CardDescription>
        </CardHeader>
        <CardContent>
          <form onSubmit={handleSocialLogin}>
            <div className="flex flex-col gap-6">
              {error && <p className="text-sm text-destructive-500">{error}</p>}
              <Button type="submit" className="w-full" disabled={isLoading}>
                {isLoading ? 'Logging in...' : 'Continue with Github'}
              </Button>
            </div>
          </form>
        </CardContent>
      </Card>
    </div>
  )
}

```

**Supabase**のクライアントで`supabase.auth.signInWithOAuth`に設定されているproviderを`Gooogle`に変更します。

```diff_typescript
      const { error } = await supabase.auth.signInWithOAuth({
-       provider: 'github',
+       provider: 'google',
        options: {
          redirectTo: `${window.location.origin}/auth/oauth?next=/protected`,
        },
      })
```

せっかくなので、ボタンの名称部分も変更しておきます。

```diff_typescript
              <Button type="submit" className="w-full" disabled={isLoading}>
-                {isLoading ? 'Logging in...' : 'Continue with Github'}
+                {isLoading ? 'Logging in...' : 'Continue with Google'}
              </Button>
```


## ローカルでテスト

ここまで来たら、いよいよローカルでテストしてみましょう!!

**Next.js**はローカルテストで動かすと、`http://localhost:3000/`のURLで検証されると思います。Supabaseは認証時のリダイレクトで利用可能なURLをセキュリティ上でチェックしている箇所があるので、Supabase
の管理画面でローカル環境のリダイレクト先URL`http://localhost:3000/**`を追加します。

Authentication > URL Configurationへ進み、Redirect URLsのAdd URLをクリック。

![Cursor_と_Authentication___Supabase.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/3120a29f-279c-4e78-bc43-3f111ffafa05.png)

![Cursor_と_Authentication___Supabase.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/8fab0622-1860-44e3-a8b0-26dfa25dbdd7.png)

`http://localhost:3000/**`を入力し、Save URLs。他にもIPベースで操作するなら、同様に追加してください。

注意点として、SupabaseのRdirect URLsにローカルのURLを追加しておかないと、ログイン時に突然Vercel側のサイトに飛ぶので、びっくりします。


設定は以上です。では、テストで実行してみます。

```
npm run dev
```

![Cursor_と_Create_Next_App.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/b90f4e4a-d49a-4061-8dce-8d357b6bc62a.png)

サイトにアクセスすると、さっそくこの画面が出てきます。

![https___qiita-image-store_s3_ap-northeast-1_amazonaws_com_0_38388_63716833-83c3-4458-a319-d8b2562a722e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/a571617a-f2ac-44ee-a1f2-cef2ea85bbc7.png)

Continue with Googleを押すと、Googleアカウントの選択が表示されます。

![https___qiita-image-store_s3_ap-northeast-1_amazonaws_com_0_38388_0c1571b8-6b6d-460e-a9db-e1e07ae35242.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/2bf2b910-d39f-438d-aee5-8f1c10d8f107.png)

サービスへのポリシー同意画面です。

![Cursor_と_Create_Next_App.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/5935b8f6-712f-4323-965d-fbe6e3c980cb.png)

ログインが成功すると、Googleアカウントのメールアドレスが画面に表示されました:tada:
ログアウトボタンも右側にあります。

![Cursor_と_Authentication___Supabase_と_login-form_tsx_—_nextjs-myapp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/0cce2011-bd44-4e49-a97a-8dfe83220317.png)

SupabaseのUsersにもログインしたユーザーが増えています。

## Vercelでも動作を確認

**Supabase**と**Vercel**のプロジェクト連携ができていると、先程のSupabase側のURL Configrationに、**Vercel**の設定が反映されています。

![Cursor_と_Authentication___Supabase.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/b537bb82-3c0a-4293-be20-6838161dd6ea.png)

先ほどの**Next.js**をGithubにpushして、Vercelへ反映させます。

![Create_Next_App.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/d2e9a556-9d79-4cc4-8710-3e0a01127b71.png)

![Create_Next_App.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/caa4b7fe-18a0-4384-aaab-c4600ddfba91.png)

無事、**Vercel**でもログイン画面が表示され、ログインが機能しました:tada:

ドメインを変更している場合は、URL Configrationのドメインも変更が必要になります。

## もう少しログインを修正

**Supabaseクライアント**の`supabase.auth.signInWithOAuth`は、Googleでログインすると、Cookieに保存されて、次回も同じアカウントでログインするようになっており、アカウントの変更がデフォルトではできません。(Cookieを削除すれば切り替えは可能）

複数アカウントを切り替えてテストしたい場合などに不便なので、毎回ログインアカウントを選択できるように変更します。

```diff_typescript
      const { error } = await supabase.auth.signInWithOAuth({
        provider: 'google',
        options: {
          redirectTo: `${window.location.origin}/auth/oauth?next=/protected`,
        },
+       queryParams: {
+           access_type: 'offline',
+           prompt: 'consent',
+       },
      })
```

## Google Auth Platformのアプリ公開について

アプリはテストモードとなっていますので、実際のサービス公開の際にはGoogle Auth Platformの`対象`のメニューからアプリを公開する必要があります。

![対象_–_Google_Auth_Platform_–_nextjs-myapp_–_Google_Cloud_コンソール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38388/3bc61cec-ecd6-445b-b531-f17abf76af84.png)

アプリの設計にもよりますが、Googleドライブのファイルを取得するなどスコープの内容によって、Googleに事前審査が必要になるそうです。

## 最後に

**Supabase UI Library**が`Social Authentication`に対応したことで、以前はマニュアルで組み込んでいたコンポーネントが標準機能のような感覚で**Next.js**にインストールできて、ますますサービス側の機能開発にリソースを当てることができるようになったと思います。

ただ、ルーティングや内部の仕組みなどは、一度マニュアルで構築してみると、構造の理解が深まる上に、この先の**Supabase**の**Row Level Security**（RLS）も絡んでくるところなので、一度は**Supabase UI Library**なしで構築してみると良いと思いました。

ここまでお読みいただき、ありがとうございました。

知見のある方から、お気づきの点などご指摘いただけると幸いです。

## 参考サイト

https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs?queryGroups=language&language=ts

https://supabase.com/docs/guides/auth/server-side/nextjs?queryGroups=router&router=app

https://supabase.com/docs/guides/auth/social-login/auth-google?queryGroups=platform&platform=web

https://qiita.com/Sicut_study/items/665ae3299f6bee349249

https://note.com/daichi_dev/n/nc11623739d29

https://zenn.dev/buenotheebiten/articles/8d37297130bf93

参考にさせていただきました。ありがとうございます。