「Next.js 13新機能のApp DirectoryとSupabaseでブログ構築」のサインイン画面にGoogle認証ボタンを追加したい。
profilesテーブルを見てもGoogle認証したユーザーが追加されない。
(「プロフィール」ページを見るとGoogleのEmailアドレスのみ表示されている。)
はる先生のソースコードに下記のようにGoogle認証ボタン(handleClick)を追加しました。
utils/SignInResponse.ts(新規追加)
export interface SignInResponse {
data: {
user: {
name: string;
email: string;
picture: string;
};
};
error: any;
}
app/components/auth/signup.tsx
'use client'
import { useRef, FormEvent, useState } from 'react'
import { useRouter } from 'next/navigation'
import { useSupabase } from '../supabase-provider'
import { FcGoogle } from "react-icons/fc";
import Link from 'next/link'
import Loading from '../../loading'
import type { SignInResponse } from '../../../utils/SignInResponse.types'
// サインアップ
const Singup = () => {
const { supabase } = useSupabase()
const router = useRouter()
const nameRef = useRef<HTMLInputElement>(null)
const emailRef = useRef<HTMLInputElement>(null)
const passwordRef = useRef<HTMLInputElement>(null)
const [loading, setLoading] = useState(false)
//ソーシャルサインイン
const handleClick= async () => {
try {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google'
}) as SignInResponse;
if (!error) {
console.log("Login successful", data);
const useremail = data.User.email;
const userName = data.User.name;
const userAvatar = data.User.picture;
// プロフィールの名前を更新
const { error: updateError } = await supabase
.from('profiles')
.update({ name: userName, avatar_url:userAvatar })
.eq('email', useremail)
} else {
console.error("Login failed", error);
setLoading(false)
return
}
} catch (err) {
console.error("An error occurred", err);
setLoading(false)
return
}
}
// 送信
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
setLoading(true)
// supabaseサインアップ
const { error: signupError } = await supabase.auth.signUp({
email: emailRef.current!.value,
password: passwordRef.current!.value,
})
if (signupError) {
alert(signupError.message)
setLoading(false)
return
}
// プロフィールの名前を更新
const { error: updateError } = await supabase
.from('profiles')
.update({ name: nameRef.current!.value })
.eq('email', emailRef.current!.value)
if (updateError) {
alert(updateError.message)
setLoading(false)
return
}
// トップページに遷移
router.push('/')
setLoading(false)
}
return (
<div className="max-w-sm mx-auto">
<form onSubmit={onSubmit}>
<div className="mb-5">
<div className="text-sm mb-1">名前</div>
<input
className="w-full bg-gray-100 rounded border py-1 px-3 outline-none focus:bg-transparent focus:ring-2 focus:ring-yellow-500"
ref={nameRef}
type="text"
id="name"
placeholder="Name"
required
/>
</div>
<div className="mb-5">
<div className="text-sm mb-1">メールアドレス</div>
<input
className="w-full bg-gray-100 rounded border py-1 px-3 outline-none focus:bg-transparent focus:ring-2 focus:ring-yellow-500"
ref={emailRef}
type="email"
id="email"
placeholder="Email"
required
/>
</div>
<div className="mb-5">
<div className="text-sm mb-1">パスワード</div>
<input
className="w-full bg-gray-100 rounded border py-1 px-3 outline-none focus:bg-transparent focus:ring-2 focus:ring-yellow-500"
ref={passwordRef}
type="password"
id="password"
placeholder="Password"
required
/>
</div>
<div className="text-center mb-5">
{loading ? (
<Loading />
) : (
<button
type="submit"
className="w-full text-white bg-yellow-500 hover:brightness-110 rounded py-1 px-8"
>
サインアップ
</button>
)}
</div>
</form>
<div className="text-center mb-5">
{loading ? (
<Loading />
) : (
<button
className="flex justify-center items-center font-bold rounded py-1 px-8 w-full border border-gray-400"
onClick={handleClick}
>
<span><FcGoogle /></span>
<span className='ml-1'>Sign in With Google</span>
</button>
)}
</div>
<div className="text-center">アカウントをお持ちですか?</div>
<div className="text-center">
<Link href="/auth/login" className="cursor-pointer font-bold">
ログイン
</Link>
</div>
</div>
)
}
export default Singup
公式ドキュメントを参考に実装してみました。
https://supabase.com/docs/guides/auth/social-login/auth-google
Google OAuth Keys とsupabaseの連携登録は行っております。
handleClick関数は、signInWithOAuthをコールするだけにします。
ここではプロフィールは更新できません。
//ソーシャルサインイン
const handleClick= async () => {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google'
})
}
supabase-listener.tsxのリスナー関数で、プロフィールテーブルを更新するとよいかと思います。
useEffect(() => {
// セッション情報取得
const getSession = async () => {
const { data } = await supabase.auth.getSession()
if (data.session) {
const id = data.session.user.id
const email = data.session.user.email
const name = data.session.user.user_metadata.name
const avatar_url = data.session.user.user_metadata.avatar_url
// ユーザーIDにとメールアドレスを状態管理に設定
setUser({
id,
email,
})
// プロフィールチェック
const { data: userData } = await supabase.from('profiles').select().eq('id', id).single()
// 名前とアバターが空のとき
if (!userData?.name && !userData?.avatar_url) {
// プロフィールの名前を更新
await supabase
.from('profiles')
.update({ name: name, avatar_url: avatar_url })
.eq('email', email)
}
}
}
ありがとうございます!
どうりで更新できないわけですね!
参考になりました。
Google認証ですね。
こちらでも試してみます。
少々お待ちください。
はる先生
このソースコードで実行しますと「if (!error) {...」の部分は通りますのでGoogle認証は出来ているようです。
しかし、この後の処理で何か足りないようでsupabaseのデータベースに保存が出来ていないようです。
お手数ですがよろしくお願いいたします。
訂正です。
ユーザー登録とprofile登録はこのソースで出来ていました。
登録出来ないのはGoogleからのレスポンスデータからname(ユーザー名)とavater_url(アイコンURL)への登録です。