Custom Access Token Hook
Customize the access token issued by Supabase Auth
The custom access token hook runs before a token is issued and allows you to add additional claims based on the authentication method used.
Claims returned must conform to our specification. Supabase Auth will check for these claims after the hook is run and return an error if they are not present.
These are the fields currently available on an access token:
Required Claims: aud
, exp
, iat
, sub
, email
, phone
, role
, aal
, session_id
Optional Claims: jti
, iss
, nbf
, app_metadata
, user_metadata
, amr
Inputs
Field | Type | Description |
---|---|---|
user_id | string | Unique identifier for the user attempting to sign in. |
claims | object | Claims which are included in the access token. |
authentication_method | string | The authentication method used to request the access token. Possible values include: oauth , password , otp , totp , recovery , invite , sso/saml , magiclink , email/signup , email_change , token_refresh , anonymous . |
_19{_19 "user_id": "8ccaa7af-909f-44e7-84cb-67cdccb56be6",_19 "claims": {_19 "aud": "authenticated",_19 "exp": 1715690221,_19 "iat": 1715686621,_19 "sub": "8ccaa7af-909f-44e7-84cb-67cdccb56be6",_19 "email": "",_19 "phone": "",_19 "app_metadata": {},_19 "user_metadata": {},_19 "role": "authenticated",_19 "aal": "aal1",_19 "amr": [ { "method": "anonymous", "timestamp": 1715686621 } ],_19 "session_id": "4b938a09-5372-4177-a314-cfa292099ea2",_19 "is_anonymous": true_19 },_19 "authentication_method": "anonymous"_19}
Outputs
Return these only if your hook processed the input without errors.
Field | Type | Description |
---|---|---|
claims | object | The updated claims after the hook has been run. |
You can allow registered admin users to perform restricted actions by granting an admin
claim to their token.
Create a profiles table with an is_admin
flag:
_10create table profiles (_10 user_id uuid not null primary key references auth.users (id),_10 is_admin boolean not null default false_10);
Create a hook:
_48create or replace function public.custom_access_token_hook(event jsonb)_48returns jsonb_48language plpgsql_48as $$_48 declare_48 claims jsonb;_48 is_admin boolean;_48 begin_48 -- Check if the user is marked as admin in the profiles table_48 select is_admin into is_admin from profiles where user_id = (event->>'user_id')::uuid;_48_48 -- Proceed only if the user is an admin_48 if is_admin then_48 claims := event->'claims';_48_48 -- Check if 'app_metadata' exists in claims_48 if jsonb_typeof(claims->'app_metadata') is null then_48 -- If 'app_metadata' does not exist, create an empty object_48 claims := jsonb_set(claims, '{app_metadata}', '{}');_48 end if;_48_48 -- Set a claim of 'admin'_48 claims := jsonb_set(claims, '{app_metadata, admin}', 'true');_48_48 -- Update the 'claims' object in the original event_48 event := jsonb_set(event, '{claims}', claims);_48 end if;_48_48 -- Return the modified or original event_48 return event;_48 end;_48$$;_48_48grant execute_48 on function public.custom_access_token_hook_48 to supabase_auth_admin;_48_48revoke execute_48 on function public.custom_access_token_hook_48 from authenticated, anon, public;_48_48grant all_48 on table public.profiles_48 to supabase_auth_admin;_48_48revoke all_48 on table public.profiles_48 from authenticated, anon, public;