diff --git a/docs/integrations/databases/supabase-and-orgs.mdx b/docs/integrations/databases/supabase-and-orgs.mdx
new file mode 100644
index 0000000000..032596ac2a
--- /dev/null
+++ b/docs/integrations/databases/supabase-and-orgs.mdx
@@ -0,0 +1,171 @@
+---
+title: Support organizations in your Clerk + Supabase application
+description: Learn how to integrate Clerk and support Clerk organizations in your Supabase application.
+---
+
+
+
+Clerk [organizations](/docs/organizations/overview) allow you to group users together and assign them specific roles and permissions, giving you a flexible and scalable way to manage users and their access to resources within your application.
+
+This guide will show you how to support Clerk organizations in your Clerk + Supabase application. If you haven't integrated Clerk with Supabase yet, follow the steps in the [guide on integrating Supabase with Clerk](/docs/integrations/databases/supabase). This guide is a direct extension of that guide.
+
+## Understand the Clerk JWT
+
+Supabase identifies the party making a request by parsing the claims of the incoming JWT. Clerk's JWT, also referred to as the [session token](/docs/backend-requests/resources/session-tokens), contains the `o.id` claim, which stands for the organization ID. This is the value that Supabase uses to identify the organization the user belongs to.
+
+The following is an example of a Clerk session token for a user in an organization, and that organization is [active](/docs/organizations/overview#active-organization). Notice the `o` claim which contains properties that identify the organization, such as the `id` and `slg` (slug) properties.
+
+```js {{ prettier: false }}
+{
+ azp: 'http://localhost:3001',
+ email: 'adaguilar@stetson.edu',
+ exp: 1744734948,
+ fea: 'o:custom-feature',
+ fva: [ 0, -1 ],
+ iat: 1744734888,
+ iss: 'https://renewing-bobcat-00.clerk.accounts.dev',
+ jti: '004f0096e5cd44911924',
+ nbf: 1744734878,
+ o: {
+ fpm: '1',
+ id: 'org_123',
+ per: 'custom-perm',
+ rol: 'admin',
+ slg: 'example-org'
+ },
+ role: 'authenticated',
+ sid: 'sess_123',
+ sub: 'user_123',
+ v: 2
+}
+```
+
+To learn about each of the claims and what they mean, see the [guide on session tokens](/docs/backend-requests/resources/session-tokens).
+
+Now that you're familiar with the Clerk JWT, let's support Clerk organizations in your Supabase application.
+
+
+ ## Enable organizations in the Clerk Dashboard
+
+ Organizations are disabled by default. To enable organizations:
+
+ 1. In the Clerk Dashboard, navigate to the [**Organizations Settings**](https://dashboard.clerk.com/last-active?path=organizations-settings) page.
+ 1. Select **Enable Organizations**.
+
+ ## Add `` to your app
+
+ The [``](/docs/components/organization/organization-switcher) component allows a user to switch between their account types - their personal account and their joined organizations. It handles all organization-related flows, including full organization management for users with the correct permissions.
+
+ Add the `` component to your app. In the following example, it's added to the header of the app, besides the `` component.
+
+ ```tsx {{ filename: 'app/layout.tsx', mark: [3, 21] }}
+ import {
+ ClerkProvider,
+ OrganizationSwitcher,
+ SignInButton,
+ SignedIn,
+ SignedOut,
+ UserButton,
+ } from '@clerk/nextjs'
+ import './globals.css'
+
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+ {children}
+
+
+
+ )
+ }
+ ```
+
+ ## Update your `task` table to include the organization ID
+
+ The `task` table needs to include the organization ID in order to support organizations. In the [Supabase SQL editor](https://supabase.com/dashboard/project/_/sql/new), run the following command to add the `org_id` column to the `tasks` table:
+
+ ```sql
+ -- Add org_id column to tasks table
+ ALTER TABLE tasks
+ ADD COLUMN org_id text DEFAULT auth.jwt()->>'o.id';
+ ```
+
+ ## Update your RLS policies to include the organization ID
+
+ You can access Clerk session token data in Supabase using the built-in `auth.jwt()` function. In the [guide on integrating Supabase with Clerk](/docs/integrations/databases/supabase), you learned how to use this function to extract the `sub` value (the user ID) from the JWT claims of the user making the request. This same function can be used to access the `o.id` value as well.
+
+ Let's update the RLS policies to include the organization ID where users can view and create tasks when either:
+
+ - They are the owner of the task (`user_id` matches) and there's no active organization
+ - The task belongs to their active organization (`org_id` matches)
+
+ You'll need to run a migration to update the RLS policies.
+
+ 1. To run migrations, you'll need to install the Supabase CLI and start the local development stack. See the [Supabase docs](https://supabase.com/docs/guides/local-development#quickstart) for instructions.
+ 1. Add the following SQL commands to the migration file:
+ ```sql
+ -- Update RLS policies to include organization ID
+ drop policy if exists "User can view their own tasks" on tasks;
+ drop policy if exists "Users must insert their own tasks" on tasks;
+
+ -- Create new policies that check both user_id and org_id
+ create policy "Users can view their own tasks"
+ on tasks
+ for select
+ using (
+ (auth.jwt()->>'sub' = user_id and auth.jwt()->>'o.id' is null) or
+ (auth.jwt()->>'o.id' = org_id)
+ );
+
+ create policy "Users must insert their own tasks"
+ on tasks
+ for insert
+ with check (
+ (auth.jwt()->>'sub' = user_id and auth.jwt()->>'o.id' is null) or
+ (auth.jwt()->>'o.id' = org_id)
+ );
+ ```
+ 1. Apply the migration to the database by executing the following command in your terminal:
+
+ > [!IMPORTANT]
+ > You may need to link your Supabase project to the CLI. You can do so by running `npx supabase link`. It may need you to sign in to your Supabase account. You can do so by running `npx supabase login`, which will open a browser window to Supabase and give you a code to paste into the CLI in order to sign in. Then you will need to run `npx supabase link` again to link the project to the CLI.
+
+ ```bash
+ npx supabase db push
+ ```
+
+ ## Test your changes
+
+ 1. Run your project and sign in. Create a task; this one will be visible if you don't have an active organization.
+ 1. The `` component will say "Personal account" which indicates that there is no [active organization](/docs/organizations/overview#active-organization). Select the component and create an organization.
+ 1. Your list of tasks should now be empty (TODO: this may not be true, I think the non-org tasks may still be visible, but I need to test once the migration TODO is done), because the "Users can view their own tasks" policy....
+ 1. Create a new task.
+ 1. To verify that the new task is only visible to users in the organization, use the `` component to invite a new user to the organization.
+ 1. Sign out and sign in as the new user. Use the `` component to verify that the user is part of the organization, and that the organization is set as active. The new task should be visible.
+
diff --git a/docs/integrations/databases/supabase.mdx b/docs/integrations/databases/supabase.mdx
index e05708fc01..a0b55103d0 100644
--- a/docs/integrations/databases/supabase.mdx
+++ b/docs/integrations/databases/supabase.mdx
@@ -324,6 +324,10 @@ This guide will have you create a new table in your [Supabase project](https://s
Run your project and sign in. Test creating and viewing tasks. Sign out and sign in as a different user, and repeat.
If you have the same tasks across multiple accounts, double check that RLS is enabled, or that the RLS policies were properly created. Check the table in the Supabase dashboard. You should see all the tasks between both users, but with differing values in the `user_id` column.
+
+ ## Clerk organizations
+
+ If you use Clerk organizations, see the guide on [integrating Supabase with Clerk organizations](/docs/integrations/databases/supabase-and-orgs).
## What does the Clerk Supabase integration do?
diff --git a/docs/manifest.json b/docs/manifest.json
index 919d8806c0..5057cafc9f 100644
--- a/docs/manifest.json
+++ b/docs/manifest.json
@@ -3309,6 +3309,10 @@
"title": "Supabase",
"href": "/docs/integrations/databases/supabase"
},
+ {
+ "title": "Supabase and Clerk Organizations",
+ "href": "/docs/integrations/databases/supabase-and-orgs"
+ },
{
"title": "Neon",
"href": "/docs/integrations/databases/neon"
diff --git a/supabase/.gitignore b/supabase/.gitignore
new file mode 100644
index 0000000000..ad9264f0b1
--- /dev/null
+++ b/supabase/.gitignore
@@ -0,0 +1,8 @@
+# Supabase
+.branches
+.temp
+
+# dotenvx
+.env.keys
+.env.local
+.env.*.local
diff --git a/supabase/config.toml b/supabase/config.toml
new file mode 100644
index 0000000000..83113e4082
--- /dev/null
+++ b/supabase/config.toml
@@ -0,0 +1,308 @@
+# For detailed configuration reference documentation, visit:
+# https://supabase.com/docs/guides/local-development/cli/config
+# A string used to distinguish different Supabase projects on the same host. Defaults to the
+# working directory name when running `supabase init`.
+project_id = "clerk-docs"
+
+[api]
+enabled = true
+# Port to use for the API URL.
+port = 54321
+# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
+# endpoints. `public` and `graphql_public` schemas are included by default.
+schemas = ["public", "graphql_public"]
+# Extra schemas to add to the search_path of every request.
+extra_search_path = ["public", "extensions"]
+# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size
+# for accidental or malicious requests.
+max_rows = 1000
+
+[api.tls]
+# Enable HTTPS endpoints locally using a self-signed certificate.
+enabled = false
+
+[db]
+# Port to use for the local database URL.
+port = 54322
+# Port used by db diff command to initialize the shadow database.
+shadow_port = 54320
+# The database major version to use. This has to be the same as your remote database's. Run `SHOW
+# server_version;` on the remote database to check.
+major_version = 15
+
+[db.pooler]
+enabled = false
+# Port to use for the local connection pooler.
+port = 54329
+# Specifies when a server connection can be reused by other clients.
+# Configure one of the supported pooler modes: `transaction`, `session`.
+pool_mode = "transaction"
+# How many server connections to allow per user/database pair.
+default_pool_size = 20
+# Maximum number of client connections allowed.
+max_client_conn = 100
+
+# [db.vault]
+# secret_key = "env(SECRET_VALUE)"
+
+[db.migrations]
+# Specifies an ordered list of schema files that describe your database.
+# Supports glob patterns relative to supabase directory: "./schemas/*.sql"
+schema_paths = []
+
+[db.seed]
+# If enabled, seeds the database after migrations during a db reset.
+enabled = true
+# Specifies an ordered list of seed files to load during db reset.
+# Supports glob patterns relative to supabase directory: "./seeds/*.sql"
+sql_paths = ["./seed.sql"]
+
+[realtime]
+enabled = true
+# Bind realtime via either IPv4 or IPv6. (default: IPv4)
+# ip_version = "IPv6"
+# The maximum length in bytes of HTTP request headers. (default: 4096)
+# max_header_length = 4096
+
+[studio]
+enabled = true
+# Port to use for Supabase Studio.
+port = 54323
+# External URL of the API server that frontend connects to.
+api_url = "http://127.0.0.1"
+# OpenAI API Key to use for Supabase AI in the Supabase Studio.
+openai_api_key = "env(OPENAI_API_KEY)"
+
+# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they
+# are monitored, and you can view the emails that would have been sent from the web interface.
+[inbucket]
+enabled = true
+# Port to use for the email testing server web interface.
+port = 54324
+# Uncomment to expose additional ports for testing user applications that send emails.
+# smtp_port = 54325
+# pop3_port = 54326
+# admin_email = "admin@email.com"
+# sender_name = "Admin"
+
+[storage]
+enabled = true
+# The maximum file size allowed (e.g. "5MB", "500KB").
+file_size_limit = "50MiB"
+
+# Image transformation API is available to Supabase Pro plan.
+# [storage.image_transformation]
+# enabled = true
+
+# Uncomment to configure local storage buckets
+# [storage.buckets.images]
+# public = false
+# file_size_limit = "50MiB"
+# allowed_mime_types = ["image/png", "image/jpeg"]
+# objects_path = "./images"
+
+[auth]
+enabled = true
+# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
+# in emails.
+site_url = "http://127.0.0.1:3000"
+# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
+additional_redirect_urls = ["https://127.0.0.1:3000"]
+# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week).
+jwt_expiry = 3600
+# If disabled, the refresh token will never expire.
+enable_refresh_token_rotation = true
+# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds.
+# Requires enable_refresh_token_rotation = true.
+refresh_token_reuse_interval = 10
+# Allow/disallow new user signups to your project.
+enable_signup = true
+# Allow/disallow anonymous sign-ins to your project.
+enable_anonymous_sign_ins = false
+# Allow/disallow testing manual linking of accounts
+enable_manual_linking = false
+# Passwords shorter than this value will be rejected as weak. Minimum 6, recommended 8 or more.
+minimum_password_length = 6
+# Passwords that do not meet the following requirements will be rejected as weak. Supported values
+# are: `letters_digits`, `lower_upper_letters_digits`, `lower_upper_letters_digits_symbols`
+password_requirements = ""
+
+[auth.rate_limit]
+# Number of emails that can be sent per hour. Requires auth.email.smtp to be enabled.
+email_sent = 2
+# Number of SMS messages that can be sent per hour. Requires auth.sms to be enabled.
+sms_sent = 30
+# Number of anonymous sign-ins that can be made per hour per IP address. Requires enable_anonymous_sign_ins = true.
+anonymous_users = 30
+# Number of sessions that can be refreshed in a 5 minute interval per IP address.
+token_refresh = 150
+# Number of sign up and sign-in requests that can be made in a 5 minute interval per IP address (excludes anonymous users).
+sign_in_sign_ups = 30
+# Number of OTP / Magic link verifications that can be made in a 5 minute interval per IP address.
+token_verifications = 30
+
+# Configure one of the supported captcha providers: `hcaptcha`, `turnstile`.
+# [auth.captcha]
+# enabled = true
+# provider = "hcaptcha"
+# secret = ""
+
+[auth.email]
+# Allow/disallow new user signups via email to your project.
+enable_signup = true
+# If enabled, a user will be required to confirm any email change on both the old, and new email
+# addresses. If disabled, only the new email is required to confirm.
+double_confirm_changes = true
+# If enabled, users need to confirm their email address before signing in.
+enable_confirmations = false
+# If enabled, users will need to reauthenticate or have logged in recently to change their password.
+secure_password_change = false
+# Controls the minimum amount of time that must pass before sending another signup confirmation or password reset email.
+max_frequency = "1s"
+# Number of characters used in the email OTP.
+otp_length = 6
+# Number of seconds before the email OTP expires (defaults to 1 hour).
+otp_expiry = 3600
+
+# Use a production-ready SMTP server
+# [auth.email.smtp]
+# enabled = true
+# host = "smtp.sendgrid.net"
+# port = 587
+# user = "apikey"
+# pass = "env(SENDGRID_API_KEY)"
+# admin_email = "admin@email.com"
+# sender_name = "Admin"
+
+# Uncomment to customize email template
+# [auth.email.template.invite]
+# subject = "You have been invited"
+# content_path = "./supabase/templates/invite.html"
+
+[auth.sms]
+# Allow/disallow new user signups via SMS to your project.
+enable_signup = false
+# If enabled, users need to confirm their phone number before signing in.
+enable_confirmations = false
+# Template for sending OTP to users
+template = "Your code is {{ .Code }}"
+# Controls the minimum amount of time that must pass before sending another sms otp.
+max_frequency = "5s"
+
+# Use pre-defined map of phone number to OTP for testing.
+# [auth.sms.test_otp]
+# 4152127777 = "123456"
+
+# Configure logged in session timeouts.
+# [auth.sessions]
+# Force log out after the specified duration.
+# timebox = "24h"
+# Force log out if the user has been inactive longer than the specified duration.
+# inactivity_timeout = "8h"
+
+# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used.
+# [auth.hook.custom_access_token]
+# enabled = true
+# uri = "pg-functions:////"
+
+# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`.
+[auth.sms.twilio]
+enabled = false
+account_sid = ""
+message_service_sid = ""
+# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead:
+auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)"
+
+# Multi-factor-authentication is available to Supabase Pro plan.
+[auth.mfa]
+# Control how many MFA factors can be enrolled at once per user.
+max_enrolled_factors = 10
+
+# Control MFA via App Authenticator (TOTP)
+[auth.mfa.totp]
+enroll_enabled = false
+verify_enabled = false
+
+# Configure MFA via Phone Messaging
+[auth.mfa.phone]
+enroll_enabled = false
+verify_enabled = false
+otp_length = 6
+template = "Your code is {{ .Code }}"
+max_frequency = "5s"
+
+# Configure MFA via WebAuthn
+# [auth.mfa.web_authn]
+# enroll_enabled = true
+# verify_enabled = true
+
+# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
+# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`,
+# `twitter`, `slack`, `spotify`, `workos`, `zoom`.
+[auth.external.apple]
+enabled = false
+client_id = ""
+# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead:
+secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)"
+# Overrides the default auth redirectUrl.
+redirect_uri = ""
+# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure,
+# or any other third-party OIDC providers.
+url = ""
+# If enabled, the nonce check will be skipped. Required for local sign in with Google auth.
+skip_nonce_check = false
+
+# Use Firebase Auth as a third-party provider alongside Supabase Auth.
+[auth.third_party.firebase]
+enabled = false
+# project_id = "my-firebase-project"
+
+# Use Auth0 as a third-party provider alongside Supabase Auth.
+[auth.third_party.auth0]
+enabled = false
+# tenant = "my-auth0-tenant"
+# tenant_region = "us"
+
+# Use AWS Cognito (Amplify) as a third-party provider alongside Supabase Auth.
+[auth.third_party.aws_cognito]
+enabled = false
+# user_pool_id = "my-user-pool-id"
+# user_pool_region = "us-east-1"
+
+# Use Clerk as a third-party provider alongside Supabase Auth.
+[auth.third_party.clerk]
+enabled = false
+# Obtain from https://clerk.com/setup/supabase
+# domain = "example.clerk.accounts.dev"
+
+[edge_runtime]
+enabled = true
+# Configure one of the supported request policies: `oneshot`, `per_worker`.
+# Use `oneshot` for hot reload, or `per_worker` for load testing.
+policy = "oneshot"
+# Port to attach the Chrome inspector for debugging edge functions.
+inspector_port = 8083
+# The Deno major version to use.
+deno_version = 1
+
+# [edge_runtime.secrets]
+# secret_key = "env(SECRET_VALUE)"
+
+[analytics]
+enabled = true
+port = 54327
+# Configure one of the supported backends: `postgres`, `bigquery`.
+backend = "postgres"
+
+# Experimental features may be deprecated any time
+[experimental]
+# Configures Postgres storage engine to use OrioleDB (S3)
+orioledb_version = ""
+# Configures S3 bucket URL, eg. .s3-.amazonaws.com
+s3_host = "env(S3_HOST)"
+# Configures S3 bucket region, eg. us-east-1
+s3_region = "env(S3_REGION)"
+# Configures AWS_ACCESS_KEY_ID for S3 bucket
+s3_access_key = "env(S3_ACCESS_KEY)"
+# Configures AWS_SECRET_ACCESS_KEY for S3 bucket
+s3_secret_key = "env(S3_SECRET_KEY)"