✨ Supabaseのトークンとuser_metadataの落とし穴:初心者向けガイド
投稿日: 2025年07月12日
こんにちは!今回はSupabaseを使った認証アプリ開発で多くの人がつまずく「トークンとユーザーデータの不一致」問題について、初心者向けにわかりやすく解説します。
特に以下のような方におすすめです:
user_metadata
に role
を入れて認可(権限)を管理したい
user_metadata
を更新したのに画面が反映されない
Supabaseのトークンってどう動いてるの?
Supabaseでは、ユーザーがログインすると「JWT(JSON Web Token)」というトークンが発行されます。
このトークンには以下の情報が埋め込まれています:
ユーザーのID
メールアドレス
user_metadata
(ニックネームやロールなど)
トークンの有効期限(例:1時間)
Supabaseの
getUser()
などで取得しているのは、このトークンに含まれる情報です。
user_metadata
を更新しても反映されない!?たとえば、ユーザーを「一般 → 管理者(role: 'ADMIN'
)」に昇格したとします。
await supabase.auth.admin.updateUserById(userId, { user_metadata: { role: 'ADMIN' } });
でも…なぜか画面で見ても、まだ role: 'USER'
のまま!?
それは、SupabaseのgetUser()
で取得しているのが“古いトークン”だからです。
JWTは一度発行されたら、内容を自動では更新できません。
user_metadata
を変更しても、トークンが更新されるまでは反映されないのです。
await supabase.auth.refreshSession();
これで新しいJWTが発行され、user_metadata
も最新になります。
await supabase.auth.signOut(); await supabase.auth.signInWithPassword({ email, password });
少し強引ですが、確実です。
実は、認可(アクセス制限)にJWTを使うのはあまり安全ではありません。
本番環境では、ユーザーの role
や 権限
はデータベースに保存し、常にDBから確認する方が安心です。
// SupabaseからユーザーIDを取得
const { data: { user } } = await supabase.auth.getUser();
// PrismaでDBからユーザーを取得(ロール付き)
const dbUser = await prisma.user.findUnique({
where: { supabaseUserId: user.id },
include: { role: true }
});
if (dbUser?.role.name !== 'ADMIN') {
return res.status(403).json({ error: 'アクセス拒否' });
}
Supabaseはとても使いやすいツールですが、「トークンの仕組み」はちょっとした落とし穴があります。
大切なのは「トークンはキャッシュされる。だから最新じゃないこともある」と知っておくこと!