Auth

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

FieldTypeDescription
user_idstringUnique identifier for the user attempting to sign in.
claimsobjectClaims which are included in the access token.
authentication_methodstringThe 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.

FieldTypeDescription
claimsobjectThe 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:


_10
create 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:


_48
create or replace function public.custom_access_token_hook(event jsonb)
_48
returns jsonb
_48
language plpgsql
_48
as $$
_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
_48
grant execute
_48
on function public.custom_access_token_hook
_48
to supabase_auth_admin;
_48
_48
revoke execute
_48
on function public.custom_access_token_hook
_48
from authenticated, anon, public;
_48
_48
grant all
_48
on table public.profiles
_48
to supabase_auth_admin;
_48
_48
revoke all
_48
on table public.profiles
_48
from authenticated, anon, public;