Documentation menu
Connect it yourselfHow do we gate Supabase Auth with Presence?

Supabase Auth Hooks

Fail-closed sign-up verification and JWT assurance claims for Supabase Auth and Postgres RLS.

Install the Auth Hooks package

terminal

npm install @decionis/presence-auth

Create the sign-up gate

supabase-hooks.ts

import { createSupabaseBeforeUserCreatedHook } from "@decionis/presence-auth/supabase"; const hook = createSupabaseBeforeUserCreatedHook({  apiHost: "https://presence.decionis.com",  apiSecret: process.env.PRESENCE_API_SECRET!,  signingSecret: process.env.SUPABASE_HOOK_SECRET!,}); export async function POST(request: Request) {  const result = await hook({    headers: Object.fromEntries(request.headers),    rawBody: await request.text(),  });  return Response.json(result.body, { status: result.status });}

Register both Auth Hooks

supabase/config.toml

[auth.hook.before_user_created]enabled = trueuri = "https://hooks.example.com/before-user-created"secrets = "env(SUPABASE_HOOK_SECRET)" [auth.hook.custom_access_token]enabled = trueuri = "https://hooks.example.com/custom-access-token"secrets = "env(SUPABASE_HOOK_SECRET)"

Enforce the assurance claim in RLS

presence-policy.sql

create policy "verified humans only"on public.transfers for insert to authenticatedwith check (  coalesce(    (auth.jwt() -> 'presence' ->> 'verified')::boolean,    false  ));

Two signed, fail-closed hooks

  1. 01

    The Before User Created hook verifies Supabase's Standard Webhooks signature over the unmodified request body, reads the Presence Session Token from user metadata, and allows only a PASS disposition by default.

  2. 02

    The Custom Access Token hook preserves Supabase's reserved claims and adds a presence assurance claim. PostgreSQL Row Level Security then denies sensitive writes unless presence.verified is true.

Verify the implementation

  • Every hook request is authenticated before Presence is called; stale, tampered, or incorrectly signed bodies return 401.

    Supabase Auth Hooks
  • PASS admits sign-up and stamps presence.verified=true; DENY, missing tokens, unresolved checks, and outages fail closed by default.

    Presence decision contract

Current limits

  • The hook endpoint and both secrets are server-side. Never expose the Presence tenant secret or the Supabase hook signing secret to a browser.
  • Install @decionis/presence-auth from npm and import the Supabase-specific handlers from @decionis/presence-auth/supabase.

One next step

Continue with the executable path.

Install the npm package