結論
認証時の詳細なログはDocker側で出力されます。
認証失敗時の詳細なログはどこの出力されるのか? を調べてみました。
それぞれのログ
Docker側に詳細なログが出力されます。(結論)
Next.js側ではメッセージか簡易すぎます。
Supabaseのダッシュボード側では見方がわかりませんでした。
例
タイトル通り、Next.js Supabase で開発していて、Webアプリでユーザー認証に成功したとき、auth.usersテーブルにデータが保存され、トリガーを使いpublicテーブルにそのデータをコピーする場合です。
認証に失敗した場合、
Next.jsのターミナルでのログでは原因の特定は困難です。
GET /?error=server_error&error_code=unexpected_failure&error_description=Database+error+saving+new+user 200 in 140ms
ターミナルに出力されるログ 👆トリガーが失敗したときに、ターミナル側で出力されるログですが、これでは原因がよくわかりません。
詳細なログはDocker側に出力されていました、
👆 詳細なログが出力されています。
後はログを読むか、コピペしてAIに聞くだけです。
- 開発中は試したい動作の開始から終了までのログが欲しいので、Logs画面の右側のゴミバケツアイコンで毎回リセットします。
Supabaseのダッシュボードのログ
Supabaseのダッシュボードではログが見れませんでした。
(コマンドを実行して出力する形式のようですが、ログを出力させるコマンドは知りません。)
Supabaseのダッシュボードの左サイドメニューのLogからログは見れるようですが、
ログ画面の上にある Insert Sourceのドロップダウンメニューのauth_logsを選ぶと、
select
timestamp, event_message, metadata
from auth_logs edge_logs limit 5
このselectを実行しても、
{
"code": 500,
"message": "An error has occurred: fetch failed",
"requestId": "cd8af92e-dd1f-4c22-9284-c2275417b08f"
}
👆このように出力されてしまい、希望通りのログが見れませんでした。
全く使い方がわかっていない状態です。
実際のコード
Next.jsでSupabaseを利用したGitHub認証
使用テーブル
auth.users <<認証成功時、このテーブルに登録されます。
public.roots <<auth.usersに登録されたデータで必要なカラムをこのrootsテーブルにコピーします。
※auth.usersはSupabaseのシステムで利用するので、アプリ側では読み込み専用になります。
挿入用関数とトリガー
-- 新規ユーザー登録時に、auth.usersに行が挿入されたとき、public.rootsに行を挿入するトリガー用の関数
create or replace function public.add_root()
returns trigger
language plpgsql
security definer set search_path = public
as $$
begin
-- GitHub認証時に得た情報を利用してrootsテーブルにデータを挿入します
begin
insert into public.roots (
id, -- ユーザー識別用ID
aud, -- 認証情報
email, -- ユーザーのメールアドレス
email_confirmed_at, -- メール確認日時
last_sign_in_at, -- 最後のサインイン日時
raw_app_meta_data, -- アプリからのメタ情報
raw_user_meta_data, -- ユーザーに関する全メタ情報(JSON)
name, -- ユーザー名(表示名)
full_name, -- フルネーム
user_name, -- ユーザー名(システム用)
created_at, -- アカウント作成日時
updated_at, -- 更新日時
deleted_at -- 削除日時
)
values (
new.id, -- auth.usersの新しいID
new.aud, -- auth.usersの認証情報
new.email, -- auth.usersのメールアドレス
new.email_confirmed_at, -- auth.usersのメール確認日時
new.last_sign_in_at, -- auth.usersの最後のサインイン日時
new.raw_app_meta_data, -- アプリメタ情報
new.raw_user_meta_data, -- ユーザーメタ情報全体
new.raw_user_meta_data ->> 'name', -- ユーザー名(表示用)
new.raw_user_meta_data ->> 'full_name', -- ユーザーのフルネーム
new.raw_user_meta_data ->> 'user_name', -- システム用ユーザー名
new.created_at, -- 作成日時
new.updated_at, -- 更新日時
new.deleted_at -- 削除日時
);
exception when others then
-- エラー発生時、詳細なエラーメッセージを出力
raise exception 'Error inserting into roots table: %', sqlerrm;
end;
return new;
end;
$$;
-- auth.usersに新しいユーザーが作成されると、public.add_root関数を実行するトリガーを設定します
create or replace trigger add_root
after insert on auth.users
for each row execute procedure public.add_root();
👇Drizzleを使ってrootsテーブルを作成します。
import {
foreignKey,
jsonb,
pgTable,
text,
timestamp,
uuid
} from 'drizzle-orm/pg-core'
import { authUsers } from 'drizzle-orm/supabase'
export const roots = pgTable(
'roots',
{
id: uuid('id').primaryKey().notNull(),
aud: text('aud'),
email: text('email').notNull(),
emailConfirmedAt: timestamp('email_confirmed_at'),
lastSignInAt: timestamp('last_sign_in_at'),
rawAppMetaData: jsonb('raw_app_meta_data'),
rawUserMetaData: jsonb('raw_user_meta_data'),
name: text('name'),
fullName: text('full_name'),
userName: text('user_name'),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at'),
deletedAt: timestamp('deleted_at')
},
(table) => [
foreignKey({
columns: [table.id],
foreignColumns: [authUsers.id]
}).onDelete('cascade')
]
)
取得したデータ
auth.usersのデータ
{
"instance_id": "00000000-0000-0000-0000-000000000000",
"id": "*****",
"aud": "authenticated",
"role": "authenticated",
"email": "*****@gmail.com",
"encrypted_password": null,
"email_confirmed_at": "2025-02-06 23:07:05.487861+00",
"invited_at": null,
"confirmation_token": "",
"confirmation_sent_at": null,
"recovery_token": "",
"recovery_sent_at": null,
"email_change_token_new": "",
"email_change": "",
"email_change_sent_at": null,
"last_sign_in_at": "2025-02-06 23:07:05.491238+00",
"raw_app_meta_data": {
"provider": "github",
"providers": [
"github"
]
},
"raw_user_meta_data": {
"iss": "https://api.github.com",
"sub": "*****",
"name": "masakinihirota",
"email": "*****@gmail.com",
"full_name": "masakinihirota",
"user_name": "masakinihirota",
"avatar_url": "https://avatars.githubusercontent.com/u/*****?v=4",
"provider_id": "*****",
"email_verified": true,
"phone_verified": false,
"preferred_username": "masakinihirota"
},
"is_super_admin": null,
"created_at": "2025-02-06 23:07:05.472528+00",
"updated_at": "2025-02-06 23:07:05.495121+00",
"phone": null,
"phone_confirmed_at": null,
"phone_change": "",
"phone_change_token": "",
"phone_change_sent_at": null,
"confirmed_at": "2025-02-06 23:07:05.487861+00",
"email_change_token_current": "",
"email_change_confirm_status": 0,
"banned_until": null,
"reauthentication_token": "",
"reauthentication_sent_at": null,
"is_sso_user": false,
"deleted_at": null,
"is_anonymous": false
}
rootsテーブルにコピーされたデータ
id,aud,email,email_confirmed_at,last_sign_in_at,raw_app_meta_data,provider,raw_user_meta_data,name,full_name,user_name,created_at,updated_at,deleted_at
*****,authenticated,*****@gmail.com,,,"{""provider"":""github"",""providers"":[""github""]}",,"{""iss"":""https://api.github.com"",""sub"":""*****"",""name"":""masakinihirota"",""email"":""*****@gmail.com"",""full_name"":""masakinihirota"",""user_name"":""masakinihirota"",""avatar_url"":""https://avatars.githubusercontent.com/u/*****?v=4"",""provider_id"":""*****"",""email_verified"":true,""phone_verified"":false,""preferred_username"":""masakinihirota""}",masakinihirota,masakinihirota,masakinihirota,2025-02-06 23:07:05.472528,2025-02-06 23:07:05.472528,
👆見にくい場合はAIにJSON形式に変換してくださいと👇お願いすると。
{
"id": "*****",
"aud": "authenticated",
"email": "*****@gmail.com",
"email_confirmed_at": null,
"last_sign_in_at": null,
"raw_app_meta_data": {
"provider": "github",
"providers": ["github"]
},
"provider": null,
"raw_user_meta_data": {
"iss": "https://api.github.com",
"sub": "*****",
"name": "masakinihirota",
"email": "*****@gmail.com",
"full_name": "masakinihirota",
"user_name": "masakinihirota",
"avatar_url": "https://avatars.githubusercontent.com/u/*****?v=4",
"provider_id": "*****",
"email_verified": true,
"phone_verified": false,
"preferred_username": "masakinihirota"
},
"name": "masakinihirota",
"full_name": "masakinihirota",
"user_name": "masakinihirota",
"created_at": "2025-02-06 23:07:05.472528",
"updated_at": "2025-02-06 23:07:05.472528",
"deleted_at": null
}