It means exactly what you think. Any logged in user can open the browser console and run
await supabase.auth.updateUser({ data: { is_admin: true } })and they're admin. user_metadata is for things like display name.
Two safe options:
A. app_metadata, which only the service role can change. Set it from the dashboard SQL editor or a server function:
update auth.users
set raw_app_meta_data = raw_app_meta_data || '{"role":"admin"}'
where email = 'you@example.com';It ends up in the JWT, so you can use it in RLS: (auth.jwt() -> 'app_metadata' ->> 'role') = 'admin'.
B. An admins table with RLS that users can't write to. Easier to manage when you have more roles.
And whatever you choose: the admin data must be protected by RLS too, not just the admin pages.