Auth Hooks
Use HTTP or Postgres Functions to customize your authentication flow
What is a hook
A hook is an endpoint that allows you to alter the default Supabase Auth flow at specific execution points. Developers can use hooks to add custom behavior that's not supported natively.
Hooks help you:
- Track the origin of user signups by adding metadata
- Improve security by adding additional checks to password and multi-factor authentication
- Support legacy systems by integrating with identity credentials from external authentication systems
- Add additional custom claims to your JWT
- Send authentication emails or SMS messages through a custom provider
The following hooks are available:
Hook | Available on Plan |
---|---|
Custom Access Token | Free, Pro |
Send SMS | Free, Pro |
Send Email | Free, Pro |
MFA Verification Attempt | Teams and Enterprise |
Password Verification Attempt | Teams and Enterprise |
Supabase supports 2 ways to configure a hook in your project:
A postgres function can be configured as a hook. The function should take in a single argument -- the event of type JSONB -- and return a JSONB object. Since the postgres function runs on your database, the request does not leave your project's instance.
Security Model
Sign the payload and grant permissions selectively in order to guard the integrity of the payload.
When you configure a postgres function as a hook, Supabase will automatically apply the following grants to the function for these reasons:
- Allow the
supabase_auth_admin
role to execute the function. Thesupabase_auth_admin
role is the postgres role that is used by Supabase Auth to make requests to your database. - Revoke permissions from other roles (e.g.
anon
,authenticated
,public
) to ensure the function is not accessible by Supabase Data APIs.
_12-- Grant access to function to supabase_auth_admin_12grant execute_12 on function public.custom_access_token_hook_12 to supabase_auth_admin;_12_12-- Grant access to schema to supabase_auth_admin_12grant usage on schema public to supabase_auth_admin;_12_12-- Revoke function permissions from authenticated, anon and public_12revoke execute_12 on function public.custom_access_token_hook_12 from authenticated, anon, public;
Create postgres functions with security invoker
We do not recommend creating postgres functions with the security definer
tag. The security definer
tag specifies that the function is to be executed with the privileges of the user that owns it. Read more about the security definer
tag in our database guide.
Using Hooks
Developing
Let us develop a Hook locally and then deploy it to the cloud. As a recap, here’s a list of available Hooks
Hook | Suggested Function Name | When it is called | What it Does |
---|---|---|---|
Send SMS | send_sms | Each time an SMS is sent | Allows you to customize message content and SMS Provider |
Send Email | send_email | Each time an Email is sent | Allows you to customize message content and Email Provider |
Custom Access Token | custom_access_token | Each time a new JWT is created | Returns the claims you wish to be present in the JWT. |
MFA Verification Attempt | mfa_verification_attempt | Each time a user tries to verify an MFA factor. | Returns a decision on whether to reject the attempt and future ones, or to allow the user to keep trying. |
Password Verification Attempt | password_verification_attempt | Each time a user tries to sign in with a password. | Return a decision whether to allow the user to reject the attempt, or to allow the user to keep trying. |
Edit config.toml
to set up the Auth Hook locally.
Modify the auth.hook.<hook_name>
field and set uri
to a value of pg-functions://postgres/<schema>/<function_name>
_10[auth.hook.<hook_name>]_10enabled = true_10uri = "pg-functions://...."
You need to assign additional permissions so that Supabase Auth can access the hook as well as the tables it interacts with.
The supabase_auth_admin
role does not have permissions to the public
schema. You need to grant the role permission to execute your hook:
_10grant execute_10 on function public.custom_access_token_hook_10 to supabase_auth_admin;
You also need to grant usage to supabase_auth_admin
:
_10grant usage on schema public to supabase_auth_admin;
Also revoke permissions from the authenticated
and anon
roles to ensure the function is not accessible by Supabase Serverless APIs.
_10revoke execute_10 on function public.custom_access_token_hook_10 from authenticated, anon;
For security, we recommend against the use the security definer
tag. The security definer
tag specifies that the function is to be executed with the privileges of the user that owns it. When a function is created via the Supabase dashboard with the tag, it will have the extensive permissions of the postgres
role which make it easier for undesirable actions to occur.
We recommend that you do not use any tag and explicitly grant permissions to supabase_auth_admin
as described above.
Read more about security definer
tag in our database guide.
There are no restrictions as to what language can be used to write a Postgres Hook. If PL/pgSQL is too difficult consider using the plv8 extension which lets you use JavaScript to define functions.
Once done, save your Auth Hook as a migration in order to version the Auth Hook and share it with other team members. Run supabase migration new
to create a migration.
If you're using the Supabase SQL Editor, there's an issue when using the ?
(Does the string exist as a top-level key within the JSON value?) operator. Use a direct connection to the database if you need to use it when defining a function.
Here is an example hook signature:
_11create or replace function public.custom_access_token_hook(event jsonb)_11returns jsonb_11language plpgsql_11as $$_11declare_11 -- Insert variables here_11begin_11 -- Insert logic here_11 return event;_11end;_11$$;
You can visit SQL Editor > Templates
for hook templates.
Deploying
In the dashboard, navigate to Authentication > Hooks
and select the appropriate function type (SQL or HTTP) from the dropdown menu.
Error Handling
You should return an error when facing a runtime error. Runtime errors are specific to your application and arise from specific business rules rather than programmer errors.
Runtime errors could happen when:
- The user does not have appropriate permissions
- The event payload received does not have required claims.
- The user has performed an action which violates a business rule.
- The email or phone provider used in the webhook returned an error.
The error is a JSON object and has the following properties:
error
An object that contains information about the error.http_code
A number indicating the HTTP code to be returned. If not set, the code is HTTP 500 Internal Server Error.message
A message to be returned in the HTTP response. Required.
Here's an example:
_10{_10 "error": {_10 "http_code": 429,_10 "message": "You can only verify a factor once every 10 seconds."_10 }_10}
Errors returned from a Postgres Hook are not retry-able. When an error is returned, the error is propagated from the hook to Supabase Auth and translated into a HTTP error which is returned to your application. Supabase Auth will only take into account the error and disregard the rest of the payload.
Outside of runtime errors, both HTTP Hooks and Postgres Hooks return timeout errors. Postgres Hooks have 2 seconds to complete processing while HTTP Hooks should complete in 5 seconds. Both HTTP Hooks and Postgres Hooks are run in a transaction do limit the duration of execution to avoid delays in authentication process.
Available Hooks
Each Hook description contains an example JSONSchema which you can use in conjunction with JSONSchema Faker in order to generate a mock payload. For HTTP Hooks, you can also use the Standard Webhooks Testing Tool to simulate a request.