create type public.admin_role as enum ('SUPER', 'MANAGER'); create table public.admin_roles ( id bigint generated by default as identity primary key, user_id uuid references public.profiles on delete cascade not null, role admin_role not null, unique (user_id, role)); create type public.admin_permission as enum ('admins.create', 'admins.read', 'admins.update', 'products.create', 'products.read', 'products.update'); create table public.admin_role_permissions ( id bigint generated by default as identity primary key, role admin_role not null, permission admin_permission not null, unique (role, permission));
insert into public.admin_role_permissions (role, permission)values ('SUPER', 'admins.create'), ('SUPER', 'admins.read'), ('SUPER', 'admins.update'), ('SUPER', 'products.create'), ('SUPER', 'products.read'), ('SUPER', 'products.update'), ('MANAGER', 'products.create'), ('MANAGER', 'products.read'), ('MANAGER', 'products.update')
-- Create the auth hook functioncreate or replace function public.custom_access_token_hook(event jsonb)returns jsonblanguage plpgsqlstableas $$ declare claims jsonb; admin_role public.admin_role; begin select role into admin_role from public.admin_roles where user_id = (event->>'user_id')::uuid; claims := event->'claims'; if admin_role is not null then -- Set the claim claims := jsonb_set(claims, '{admin_role}', to_jsonb(admin_role)); else claims := jsonb_set(claims, '{admin_role}', 'null'); end if; -- Update the 'claims' object in the original event event := jsonb_set(event, '{claims}', claims); -- Return the modified or original event return event; end;$$; grant usage on schema public to supabase_auth_admin; grant execute on function public.custom_access_token_hook to supabase_auth_admin; revoke execute on function public.custom_access_token_hook from authenticated, anon, public; grant all on table public.admin_rolesto supabase_auth_admin; revoke all on table public.admin_roles from authenticated, anon, public; create policy "Allow auth admin to read admin roles" ON public.admin_rolesas permissive for selectto supabase_auth_adminusing (true)
Supabase 대시보드 > Auth Hooks에서 Customize Access Token (JWT) Claims hook 추가
Customize Access Token (JWT) Claims hook
create or replace function public.authorize_admin( requested_permission admin_permission)returns boolean as $$declare bind_permissions int; admin_role public.admin_role;begin select (auth.jwt() ->> 'admin_role')::public.admin_role into admin_role; select count(*) into bind_permissions from public.admin_role_permissions where admin_role_permissions.permission = requested_permission and admin_role_permissions.role = admin_role; return bind_permissions > 0;end;$$ language plpgsql stable security definer set search_path = '';
create policy "Allow authorized admin create access" on public.products for insert with check ( (SELECT authorize_admin('products.create')) );create policy "Allow authorized admin read access" on public.products for select using ( (SELECT authorize_admin('products.read')) );create policy "Allow authorized admin update access" on public.products for update using ( (SELECT authorize_admin('products.update')) );