Clerk and Supabase are the most popular auth + database combination in the Next.js ecosystem. But connecting them correctly — so that Supabase's Row-Level Security can verify the user's Clerk identity — requires a specific JWT template setup. This guide covers the complete integration.

The Problem: Two Different Auth Systems

Clerk manages authentication and issues its own JWTs. Supabase has its own auth system and uses its own JWTs for RLS. To use Clerk for auth and Supabase for data storage with RLS, you need Supabase to accept Clerk's JWTs — which requires a JWT template.

Step 1: Create a Supabase JWT Template in Clerk

  1. Go to the Clerk Dashboard > JWT Templates
  2. Click New Template > Supabase
  3. Clerk pre-fills the correct claims structure
  4. Copy the signing key from the template
  5. In the Supabase Dashboard > Settings > API > JWT Secret, paste this key

The template creates JWTs with the claims Supabase expects, signed with a key Supabase trusts.

Step 2: Create a Supabase Client That Uses the Clerk JWT

// lib/supabase.ts
import { createClient } from '@supabase/supabase-js';
import { useAuth } from '@clerk/nextjs';
 
// Client-side hook
export function useSupabaseClient() {
  const { getToken } = useAuth();
 
  return createClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      global: {
        fetch: async (url, options = {}) => {
          const clerkToken = await getToken({ template: 'supabase' });
          const headers = new Headers(options.headers);
          headers.set('Authorization', `Bearer ${clerkToken}`);
          return fetch(url, { ...options, headers });
        },
      },
    }
  );
}
// Server-side (Route Handlers and Server Actions)
import { auth } from '@clerk/nextjs/server';
import { createClient } from '@supabase/supabase-js';
 
export async function createServerSupabaseClient() {
  const { getToken } = auth();
  const clerkToken = await getToken({ template: 'supabase' });
 
  return createClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      global: {
        headers: { Authorization: `Bearer ${clerkToken}` },
      },
    }
  );
}

Step 3: Write RLS Policies Using Clerk's User ID

The Clerk JWT includes a sub claim containing the Clerk user ID. In Supabase RLS policies, auth.jwt()->>'sub' gives you this value.

-- Use auth.jwt()->>'sub' for the Clerk user ID
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
 
CREATE POLICY "Users see their own documents"
  ON documents FOR SELECT
  USING (auth.jwt()->>'sub' = clerk_user_id);
 
CREATE POLICY "Users can insert their own documents"
  ON documents FOR INSERT
  WITH CHECK (auth.jwt()->>'sub' = clerk_user_id);
Store the Clerk user ID in a column named clerk_user_id (or user_id) in your tables. Reference it in RLS policies using auth.jwt()-->>>'sub'. Do not try to join against Supabase's auth.users table — Clerk manages users, not Supabase Auth.

Step 4: Storing Clerk's org_id for Multi-Tenant RLS

If you're using Clerk Organizations, include org_id in the JWT template so you can scope data to organisations.

// JWT Template claims (in Clerk Dashboard)
{
  "sub": "{{user.id}}",
  "org_id": "{{org.id}}",
  "org_role": "{{org.role}}"
}
-- Org-scoped RLS policy using JWT claim
CREATE POLICY "Org members see org documents"
  ON documents FOR SELECT
  USING (org_id = (auth.jwt()->>'org_id'));

Using the Integration in a Route Handler

// app/api/documents/route.ts
import { createServerSupabaseClient } from '@/lib/supabase';
import { auth } from '@clerk/nextjs/server';
 
export async function GET() {
  const { userId } = auth();
  if (!userId) return Response.json({ error: 'Unauthorized' }, { status: 401 });
 
  const supabase = await createServerSupabaseClient();
 
  // RLS automatically filters to this user's documents
  const { data, error } = await supabase.from('documents').select('*');
 
  if (error) return Response.json({ error: error.message }, { status: 500 });
  return Response.json(data);
}
Metadata Value
Title Clerk + Supabase Integration: JWT Templates and Row-Level Security
Tool Clerk
Primary SEO keyword clerk supabase integration
Secondary keywords clerk supabase JWT template, clerk supabase RLS, clerk supabase next.js
Estimated read time 8 minutes
Research date 2026-04-14