"Supabase Multi Tenant Auth Custom Access Token Hook"
Supabase multi tenant auth custom access token hook: add org_id + role to the JWT, enforce tenant isolation with RLS, resolve tenants from subdomains.
Last updated: October 3, 2026 Every SaaS app eventually needs the same thing: one database, many customers, and a hard guarantee that Acme Corp can never see Globex's data. This Supabase multi tenant auth custom access token hook guide shows you the production pattern — an org_id on every tenant-scoped table, a Custom Access Token Hook that stamps the user's active organization and role into the JWT, and RLS policies that read those claims so isolation is enforced by Postgres itself, not by hoping your app code remembers the filter. What you'll learn Shared-schema multi-tenancy with org_id : the tables you need What the Custom Access Token Hook is and how to enable it Writing the hook function that injects org_id and org_role JWT claims RLS policies for tenant isolation using auth.jwt() claims Resolving the tenant from a subdomain in Flutter Shared schema vs schema-per-tenant: the honest tradeoff Common mistakes that leak tenant data The Data Model: Organizations and Memberships Shared-schema multi-tenancy means one set of tables with an org_id column on everything tenant-scoped. You need exactly two foundation tables before anything else: -- Run in the Supabase SQL editor create table public.organizations ( id uuid primary key default gen_random_uuid(), name text not null, slug text not null unique, created_at timestamptz not null default now() ); create table public.organization_members ( org_id uuid not null references public.organizations(id) on delete cascade, user_id uuid not null references auth.users(id) on delete cascade, role text not null default 'member' check (role in ('owner', 'admin', 'member')), created_at timestamptz not null default now(), primary key (org_id, user_id) ); alter table…