Next.js + Supabaseでソーシャルログインを実装する方法

WEBサービスを運営する上で、重要な点が1つあります。それは『サービスを使うまでのハードルを以下に低くするか』というものです。

もしユーザー登録やログインの際、フォームに入力をしなければいけない仕様にした場合、70~80%もの人が離脱してしまう、と統計がでています。

しかしSNS認証を可能にし、1クリックで登録できるようにしたらどうでしょうか。
圧倒的に多くのユーザーを獲得することができるでしょう。

今回は以前作成した認証機能のリポジトリにソーシャルログイン機能を追加して、より簡単にログインできるように変更します。
特に利用率が高いGoogleとFacebookでのログインを今回は作成します。

目次

Supabase側の設定

①:Supabaseプロジェクトの作成

Supabaseにログイン(登録していなければアカウント登録から)して、
トップページの「New Project」を押します。

すると、下記の様な画面が表示されます。

適当なプロジェクト名とデータベースのパスワードを入れて新しいプロジェクトを作成しましょう。
※Regionはできれば自分の住んでいる地域の近くがいいです。私は日本にしました。

Next.js事前準備

①:認証機能のリポジトリをクローン

今回はこちらの記事で紹介している認証機能(Supabase Auth)を元に実装を進めたいので、
まずはこちらの記事内にあるgithubのリンク から`git clone`してリポジトリを持ってきてください。

②:起動確認

Supabase Authが正しく動くかをまず確認しましょう。

クローンしたプロジェクトの直下に`.env.local`を新規作成し、
内容を下記の通り入力します

# Update these with your Supabase details from your project settings > API
# https://app.supabase.com/project/_/settings/api
NEXT_PUBLIC_SUPABASE_URL={ここにProject URLを入れる}
NEXT_PUBLIC_SUPABASE_ANON_KEY={ここにProject API Anon Keyを入れる}

それぞれここに〜〜入れると書かれている部分へ
Supabaseダッシュボードの`Project Settings`の`API`より、必要な情報をコピーします。

コピーが終わったら、

npm install

を実行し、更に

npm run dev

を実行します。

下記の画面が表示されるか確認してください。

Sign Upで登録したメールアドレスでLoginを行い、Profileページが表示されたらOKです。

Googleログインの設定

Googleのソーシャルログイン機能の実装を行います。
実装には、

  1. GCPでのOAuth設定
  2. SupabaseとGCPの連携
  3. Next.jsへの実装

の3ステップが必要です。

まずはGCPの設定から作成します。

GCPでのOAuth設定 〜 SupabaseとGCPの連携

Googleのソーシャルログインを行うためには、Google側の認証機能をONにする必要があります。
そのためにGCPでプロジェクトを作成しましょう。

https://cloud.google.com/?hl=ja上記サイトにアクセスし、Googleアカウントでログインします。

`新しいプロジェクト`を押し、新規のプロジェクトを作成します。

作成したプロジェクトで、左上メニューから`OAuth同意画面`をクリックします。

ユーザの種類を`外部`(External)にし、そのままステップを進んで同意画面を作成します。
作成後下記のようなステータスになっていればOKです

次に左上メニューから`認証情報`をクリックします。

`認証情報を作成`から`OAuthクライアントID`をクリックします。

`ウェブ アプリケーション`を選択し、
`承認済みのリダイレクトURI`にSupabaseのダッシュボード→`Authentication`→`Providers`→`Google`の`Callback URL (for OAuth)`をコピーして追加します。
その後、作成をクリックしてください。

クライアントIDの作成が完了すると、IDとシークレットが確認できる画面が表示されるため、
これらの情報を先ほど開いたSupabaseの`Google`の認証設定画面の`Client ID (for OAuth)`、`Client Secret (for OAuth)`に入力します。
その後、`Enable Sign in with Google`にチェックを入れ、右下部の保存ボタンを押してSupabaseとGCPの連携を完了します。

Next.jsへの実装

components/modal/signinForm.tsx

サインインフォームをソーシャルログインに合わせて修正します。

"use client"
import { Dispatch, SetStateAction } from "react";
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'
import GoogleButton from "../socialLogin/googleButton";
import FacebookButton from "../socialLogin/facebookButton";
import Link from "next/link";

export default function SignInForm(props: {
  showModal: Dispatch<SetStateAction<boolean>>;
}) {
  const { showModal } = props;
  const supabase = createClientComponentClient()

  const handleSocialLogin = async (prov: any) => {
    const { data, error } = await supabase.auth.signInWithOAuth({
      provider: prov,
      options: {
        queryParams: {
          access_type: 'offline',
          prompt: 'consent',
        },
      },
    })

    if (error) {
      console.log(error);
      return
    }

  }

  return (
    <>
      <form action="/auth/login" method="post" className="space-y-4 mb-10">
        <div>
          <label
            htmlFor="email"
            className="block mb-2 text-sm font-medium text-gray-900"
          >
            メールアドレス
          </label>
          <input
            type="email"
            name="email"
            id="email"
            className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
            placeholder="name@company.com"
            required
          />
        </div>
        <div>
          <label
            htmlFor="password"
            className="block mb-2 text-sm font-medium text-gray-900"
          >
            パスワード
          </label>
          <input
            type="password"
            name="password"
            id="password"
            placeholder="••••••••"
            className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
            required
          />
        </div>
        <div className="text-right">
          <Link className="font-medium text-blue-600 dark:text-blue-500 hover:underline" href={`${location.origin}/resetPassword`} onClick={() => showModal(false)}>パスワードを忘れた場合</Link>
        </div>
        <div>
          <button className="w-full text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center">
            サインイン
          </button>
        </div>
      </form>
      <div>
        <GoogleButton handleClickMethod={handleSocialLogin}></GoogleButton>
      </div>
    </>
  );
}

ポイントは、ソーシャルログイン用の共通関数です。

const handleSocialLogin = async (prov: any) => {
    const { data, error } = await supabase.auth.signInWithOAuth({
      provider: prov,
      options: {
        queryParams: {
          access_type: 'offline',
          prompt: 'consent',
        },
      },
    })

    if (error) {
      console.log(error);
      return
    }

  }

`prov`という値でログインに使うプロバイダを変更できるようにしています。
(”google”, “facebook”などの文字列が入ります。)

components/socialLogin/googleButton.tsx

グーグルのログインボタンのUIを作成します。

公式でボタンを生成するための仕組みが用意されているため、こちらのコードを参考にtsx化しましょう。
https://developers.google.com/identity/branding-guidelines?hl=ja

作成したUIが下記になります。

interface Props {
  handleClickMethod: any;
}

export default function GoogleButton({ handleClickMethod }: Props) {
  return (
    <button onClick={() => handleClickMethod("google")} className="gsi-material-button">
      <div className="gsi-material-button-state"></div>
      <div className="gsi-material-button-content-wrapper">
        <div className="gsi-material-button-icon">
          <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" xmlnsXlink="http://www.w3.org/1999/xlink" className="block">
            <path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"></path>
            <path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"></path>
            <path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"></path>
            <path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"></path>
            <path fill="none" d="M0 0h48v48H0z"></path>
          </svg>
        </div>
        <span className="gsi-material-button-contents">Sign in with Google</span>
        <span className="hidden">Sign in with Google</span>
      </div>
      <style jsx>{`
      .gsi-material-button {
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  -webkit-appearance: none;
  background-color: WHITE;
  background-image: none;
  border: 1px solid #747775;
  -webkit-border-radius: 4px;
  border-radius: 4px;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  color: #1f1f1f;
  cursor: pointer;
  font-family: 'Roboto', arial, sans-serif;
  font-size: 14px;
  height: 40px;
  letter-spacing: 0.25px;
  outline: none;
  overflow: hidden;
  padding: 0 12px;
  position: relative;
  text-align: center;
  -webkit-transition: background-color .218s, border-color .218s, box-shadow .218s;
  transition: background-color .218s, border-color .218s, box-shadow .218s;
  vertical-align: middle;
  white-space: nowrap;
  width: auto;
  max-width: 400px;
  min-width: min-content;
}

.gsi-material-button .gsi-material-button-icon {
  height: 20px;
  margin-right: 12px;
  min-width: 20px;
  width: 20px;
}

.gsi-material-button .gsi-material-button-content-wrapper {
  -webkit-align-items: center;
  align-items: center;
  display: flex;
  -webkit-flex-direction: row;
  flex-direction: row;
  -webkit-flex-wrap: nowrap;
  flex-wrap: nowrap;
  height: 100%;
  justify-content: space-between;
  position: relative;
  width: 100%;
}

.gsi-material-button .gsi-material-button-contents {
  -webkit-flex-grow: 1;
  flex-grow: 1;
  font-family: 'Roboto', arial, sans-serif;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: top;
}

.gsi-material-button .gsi-material-button-state {
  -webkit-transition: opacity .218s;
  transition: opacity .218s;
  bottom: 0;
  left: 0;
  opacity: 0;
  position: absolute;
  right: 0;
  top: 0;
}

.gsi-material-button:disabled {
  cursor: default;
  background-color: #ffffff61;
  border-color: #1f1f1f1f;
}

.gsi-material-button:disabled .gsi-material-button-contents {
  opacity: 38%;
}

.gsi-material-button:disabled .gsi-material-button-icon {
  opacity: 38%;
}

.gsi-material-button:not(:disabled):active .gsi-material-button-state, 
.gsi-material-button:not(:disabled):focus .gsi-material-button-state {
  background-color: #303030;
  opacity: 12%;
}

.gsi-material-button:not(:disabled):hover {
  -webkit-box-shadow: 0 1px 2px 0 rgba(60, 64, 67, .30), 0 1px 3px 1px rgba(60, 64, 67, .15);
  box-shadow: 0 1px 2px 0 rgba(60, 64, 67, .30), 0 1px 3px 1px rgba(60, 64, 67, .15);
}

.gsi-material-button:not(:disabled):hover .gsi-material-button-state {
  background-color: #303030;
  opacity: 8%;
}

      `}
      </style>
    </button>
  );
}

Googleボタンを追加したフォームは下記のような見た目になります。

動作確認

実際に動くかどうか確認してみましょう。
Googleのログインボタンを押すと下記の画面が表示されます。

アカウントを選択すると、ログイン確認画面が表示されます。

次へを押すと「ログインに成功しました。」と表示されます。

Supabaseダッシュボード→`Authentication`を見ると、Googleでログインしたアカウントが追加されていることがわかります。

Facebookログインの設定

基本的にGoogleと似ています。

  1. Facebook開発者向けページでのアプリ作成
  2. Supabaseとアプリの連携
  3. Next.jsへの実装

の3ステップが必要です。

Facebook開発者向けページでのアプリ作成 〜 Supabaseとアプリの連携

https://developers.facebook.com/にログインします。(Facebookの開発者アカウントがない場合は作成してください。)

`アプリ`メニューを開き、`アプリを作成`をクリックします。

`Facebookログインでの〜〜〜`をチェックして、次へをクリックします。

次の画面は`ゲームを構築していません`をチェックして進みます。
最後の画面でアプリ名を入力してアプリを作成します。

Supabaseのダッシュボード→`Authentication`→`Providers`→`Facebook`の`Callback URL (for OAuth)`をコピーします。

Facebookの作成したアプリのダッシュボードから`ユースケース`→`カスタマイズ`→`設定に移動`から
`有効なOAuthリダイレクトURI`に先ほどコピーしたURLを追加し保存します。

`カスタマイズ`画面に戻り、`アクセス許可`のメールアドレスの右に追加ボタンが表示されていたら、それを押してください。
`Email`のステータスを`テスト準備完了`に変更します。

Facebookアプリのダッシュボードのトップページに戻り、`アプリの設定`→`ベーシック`をクリックします。
表示された`アプリID`と`app secret`をSupabaseのダッシュボード→`Authentication`→`Providers`→`Facebook`にそれぞれ入力します。
その後、`Facebook enabled`にチェックを入れ、右下部の保存ボタンを押してSupabaseとFacebookの連携を完了します。

Next.jsへの実装

components/modal/signinForm.tsx

先ほど作成したサインインフォームのGoogleButtonの下にFacebookのUIを追加します。

<div>
 <FacebookButton handleClickMethod={handleSocialLogin}></FacebookButton>
</div>

components/socialLogin/facebookButton.tsx

本来はFacebookのログインボタンを公式(下記URL)から生成しますが、
https://developers.facebook.com/docs/facebook-login/web/login-button/
HTTPSでないと利用できず、localhostで確認が手間なので自前でボタンを作成します。

interface Props {
  handleClickMethod: any;
}

export default function FacebookButton({ handleClickMethod }: Props) {
  return (
    <>
      <button onClick={() => handleClickMethod("facebook")} className="mt-2 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 focus:outline-none" >Facebook ログイン</button>
    </>
  );
}

フォームの見た目は下記のようになります。

動作確認

実際に動くかどうか確認してみましょう。

Facebookのログインボタンを押すと、Facebookへのログインを促される画面が表示されます。

メールアドレス・パスワードを入力してログインすると「ログインに成功しました」と表示されます。

Supabaseダッシュボード→`Authentication`を見ると、Facebookでログインしたアカウントが追加されていることがわかります。

※Facebookの開発者向けアプリは、実際に利用する場合、公開する必要がありますが、公開前レビューに時間がかかるため今回は開発中のものをそのまま利用しています。

まとめ

GoogleとFacebookのソーシャルログインの作成をSupabaseで行う方法について、理解できたかと思います。
Supabaseではその他様々なプロバイダに対応しており、利用方法もSupabaseのサイトから確認できるため、ぜひ他のSNSも試してみてください。
https://supabase.com/docs/guides/auth/social-login

ソーシャルログインのプロバイダ一覧

その他参考資料など

今回のgithubはこちらになります。

またTodoONada株式会社では、チャットシステム以外にも、ストレージを利用した画像アプリやTodoアプリ等の作成方法についてご紹介しています。
ぜひこちらもご覧ください!

お問合せ&各種リンク

presented by

  • システム開発、アプリ開発
  • マッチングアプリ開発
  • インフラ構築支援等、なんでもご相談ください。
よかったらシェアしてね!
  • URLをコピーしました!
目次