【supabase】Google認証の実装方法
投稿日: 2024年12月19日
学習アプリのプロトタイプ開発終わりました。駆け抜けた~!!
これからはいただいたフィードバックを元に修正を重ねて本実装に入るのだと思います。
引き続き頑張ります!!
今回、サインアップ、サインインを相当時短ですることができるGoogle認証機能を使ってユーザー登録機能を実装したのですが、「やろうとしていた!」とか「やってみたい!」って声がスクール内であったので、コードについて詳しく振り返って情報共有させていただきます!
"@supabase/supabase-js": "^2.47.2",
"next": "15.0.4",
GCPの設定とsupabaseの管理画面で設定が必要です!
ここ私やってなくて・・端折らせてください💦w
signInWithOAuthメソッドを使って認証
リダイレクト先でDBユーザー登録処理
ログイン後の画面へ遷移
ザっとこんな流れです。
DBユーザー登録以外すべてクライアントサイドで処理します!
サインインボタン押下時に実行する関数で下記のように処理します。
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でクエリパラメータとして取得しようといていて、できないできない嘆いていたのは私です☆
リダイレクト先の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最高ですよね!!
レビュー前は違う形で処理していて(リダイレクト先の処理が違った)、ちゃんと動いてはいたんですけど、このやり方が正しいみたいです。
ぜひ参考に~!!