😊
Nuxt + SupabaseでGoogleログインをGoogle pre-builtで実装する
基本はドキュメント通りに設定・実装すれば問題ないが、地味に悩んだところがあったのでメモ。
Google クライアントライブラリのロード
ドキュメントでは script タグからロードしろとあるが、Nuxt で実装する場合、基本的に script タグを直接実装することはない。
対応方法
これは useHead を使用することで解決できる。
<script setup lang="ts">
useHead({
script: [
{
src: "https://accounts.google.com/gsi/client",
async: true,
},
],
});
</script>
Google ログイン成功時のコールバック関数の定義
Google の HTML コードジェネレーターでログインボタンを生成すると以下のような HTML を得られる。
<div
id="g_id_onload"
data-client_id="クライアントID"
data-context="signin"
data-ux_mode="popup"
data-callback="handleSignInWithGoogle"
data-auto_prompt="false"
data-nonce=""
data-auto_select="true"
data-itp_support="true"
data-use_fedcm_for_prompt="true"
></div>
ここで、data-callback に指定するコールバック関数handleSignInWithGoogle
はグローバルにアクセス可能である必要がある。
Create a handleSignInWithGoogle function that takes the CredentialResponse and passes the included token to Supabase. The function needs to be available in the global scope for Google's code to find it.
これは Nuxt や Vue の文脈とは関係なしにglobal scope
である必要があるため、plugin として実装して$
でアクセスするとかそういう話ではない。ブラウザのデベロッパーツールで開いたコンソールからアクセスできなきゃいけないようなイメージ。
対応
window オブジェクトに関数をもたせる方法で対応可能。
<script setup lang="ts">
const supabase = useSupabaseClient();
const handleSignInWithGoogle = async (response: { credential: string }) => {
const { data, error } = await supabase.auth.signInWithIdToken({
provider: "google",
token: response.credential,
});
// ...
};
onMounted(() => {
(window as any).handleSignInWithGoogle = handleSignInWithGoogle;
});
onUnmounted(() => {
delete (window as any).handleSignInWithGoogle;
});
</script>
最適な方法かは不明だが、ログインボタン用のコンポーネント内で関数を定義して Unmount 時に削除してあげれば、グローバルスコープではあるけど実際のスコープを小さくできるのでよさげな気がする。
Discussion