Open4

Supabase で auth.user を削除する

プログラミングをするパンダプログラミングをするパンダ

Storage に画像をアップロードしている場合、auth.user を削除しようとすると失敗する。

例えば、avatars という名前の bucket に画像をアップロードしている場合は、以下のような select のクエリを発行すると、storage の情報が返ってくる。

select * from storage.objects;
id bucket_id name owner created_at updated_at last_accessed_at metadata path_tokens
obj-id avatars img.png uid 2021-11-16T14:21:05.826Z 2021-11-16T14:21:05.826Z 2021-11-16T14:21:05.826Z {"size":24292,"mimetype":"image/png","cacheControl":"max-age=31536000"} ["img.png"]

この画像を削除するためには、以下のような DELETE のコマンドを発行する。

DELETE FROM storage.objects WHERE owner = 'uid';

これでテーブルからデータが消えるし、storage からもユーザーが投稿した画像が消える。

プログラミングをするパンダプログラミングをするパンダ

しかし、ユーザーの退会ごとに上記のような SQL を発行することはできない。

そこで、以下のような function (ストアドファンクション)を用意する。

create or replace function public.handle_delete_user_created_objects()
returns boolean as $$
begin
    delete from storage.objects where owner = auth.uid();
    return true;
end;
$$ language plpgsql security definer;

https://www.postgresql.jp/docs/9.2/sql-createfunction.html

すると、Database > functions に先ほど作成した関数が表示される。

この関数の API Doc を閲覧すると、以下のような JS のコードから関数を呼び出し可能だとわかる。

let { data, error } = await supabase
  .rpc('handle_delete_user_created_objects')

if (error) console.error(error)
else console.log(data)

そこで、サーバー側で auth.userユーザーの削除処理をする前に、クライアント側からこの関数を実行すれば、全ての画像を削除することができる。

クライアント側で画像を削除した段階で、storage.objects の auth.user に対する依存関係がなくなるからだ。

// client
const { data, error } = await supabase.rpc('handle_delete_user_created_objects')
// server
const { error } = await supabase.auth.api.deleteUser(id, serviceRoleKey)

これでユーザーを削除することができた。

プログラミングをするパンダプログラミングをするパンダ

なお、上記でユーザーに紐づく public なテーブルの行は、users テーブルからのリレーションの条件 on delete cascade で全て自動的に削除されるものとする。

on delete cascade を設定していない場合、public なテーブルから user に関連する行を削除しなければならない