【supabase】Google認証の実装方法

【supabase】Google認証の実装方法

投稿日: 2024年12月19日

Tips
学習振り返り
要約
  • 学習アプリのプロトタイプ開発が完了し、Google認証機能を使ったユーザー登録機能を実装した。
  • 認証後のリダイレクト先でアクセストークンを取得し、バックエンドでユーザー情報を確認して登録する処理を行った。
  • Supabaseを用いたGoogle認証機能の実装が簡単にできることを実感し、レビューを通じて処理方法の改善ができた。

はじめに

学習アプリのプロトタイプ開発終わりました。駆け抜けた~!!

これからはいただいたフィードバックを元に修正を重ねて本実装に入るのだと思います。

引き続き頑張ります!!

今回、サインアップ、サインインを相当時短ですることができるGoogle認証機能を使ってユーザー登録機能を実装したのですが、「やろうとしていた!」とか「やってみたい!」って声がスクール内であったので、コードについて詳しく振り返って情報共有させていただきます!

環境

"@supabase/supabase-js": "^2.47.2",
"next": "15.0.4",

事前準備

GCPの設定とsupabaseの管理画面で設定が必要です!

ここ私やってなくて・・端折らせてください💦w


処理の流れ

  1. signInWithOAuthメソッドを使って認証

  2. リダイレクト先でDBユーザー登録処理

  3. ログイン後の画面へ遷移

ザっとこんな流れです。

DBユーザー登録以外すべてクライアントサイドで処理します!

実装

signInWithOAuth

サインインボタン押下時に実行する関数で下記のように処理します。

const { error } = await supabase.auth.signInWithOAuth({
        provider: 'google',
        options: {
          redirectTo: `${process.env.NEXT_PUBLIC_APP_BASE_URL}/oauth/callback/google`,
        },
})

リダイレクト先は認証後専用で用意するページです。

Google認証後のリダイレクト先URL(callbackurl)にはフラグメント(#)でaccess_tokenが付与されているので特別なURLになっています!

フラグメントなの気付かずuseSearchParamsでクエリパラメータとして取得しようといていて、できないできない嘆いていたのは私です☆

リダイレクト先でDBユーザー登録

リダイレクト先のapp\oauth\callback\google\page.tsx

"use client";
import { useRouter } from "next/navigation";
import { api } from "@/app/_utils/api";
import { GoogleRequest } from "@/app/api/oauth/google/_types/GoogleRequest";
import { useEffect, useState } from "react";
export default function OAuthCallback() {
  const router = useRouter();
  const [accessToken, setAccessToken] = useState<string | null>(null);

  useEffect(() => {
    const hash = window.location.hash.substring(1);
    const params = new URLSearchParams(hash);
    const token = params.get("access_token");
    setAccessToken(token);
  }, []);

  useEffect(() => {
    const postUser = async () => {
      if (!accessToken) return;
      try {
        await api.post<GoogleRequest, { message: string }>(
          "/api/oauth/google",
          { accessToken }
        );
        router.replace("/courses/6/2");
        return;
      } catch (e) {
        console.error("ユーザー情報の登録に失敗:", e);
      }
    };
    postUser();
  }, [accessToken]);

  return <div className="text-center">読込み中...</div>;
}

処理自体は本当に単純なことで、URLからaccess_tokenを取得して、その内容をリクエストボディにしてPOSTリクエストしているだけです。

このページはユーザー情報の確認と登録を行うだけなのでずっと読込み中です。

バックエンドは、

import { NextRequest, NextResponse } from "next/server";
import { buildPrisma } from "@/app/_utils/prisma";
import { supabase } from "@/app/_utils/supabase";
import { buildError } from "@/app/api/_utils/buildError";
import { GoogleRequest } from "./_types/GoogleRequest";
export const POST = async (request: NextRequest) => {
  const prisma = await buildPrisma();
  const { accessToken }: GoogleRequest = await request.json();
  try {
    const { data, error } = await supabase.auth.getUser(accessToken);
    if (error) {
      console.error("Supabase error:", error.message);
      throw new Error("Unauthorized");
    }
    const user = await prisma.user.findUnique({
      where: {
        supabaseUserId: data.user.id,
      },
    });
    if (user)
      return NextResponse.json({ message: "既存ユーザー" }, { status: 200 });

    await prisma.user.create({
      data: {
        supabaseUserId: data.user.id,
        name: data.user.user_metadata.full_name,
        email: data.user.user_metadata.email,
      },
    });

    return NextResponse.json(
      {
        user,
        message: "新規ユーザー登録",
      },
      { status: 200 }
    );
  } catch (e) {
    return buildError(e);
  }
};

こんな感じです。

トークンの内容からカレントユーザーの情報を取得して、取得出来たらDBのuser情報を確認、データが存在したら何もせずreturn、存在しなければ初めてのログインとしてユーザー登録をしてreturnという流れです!

おわりに

Google認証機能が、ほんの数行のコードで実現できてしまうって、supabase最高ですよね!!

レビュー前は違う形で処理していて(リダイレクト先の処理が違った)、ちゃんと動いてはいたんですけど、このやり方が正しいみたいです。

ぜひ参考に~!!

シェア!

Threads
user
吉本茜
山口在住/二児の母/育休中
Loading...
記事一覧に戻る
Threads
0