Supabase RLS Policies for AI Agent Writes
AI agents writing directly to your database sounds risky—until you lock it down with Supabase RLS policies that enforce row-level security based on agent identity and request context.
Why RLS Matters for AI Agent Systems
When you give Claude or another AI agent database write permissions, you're essentially granting code execution privileges. RLS (Row-Level Security) is your safety net: it ensures agents can only modify rows they're explicitly allowed to touch, regardless of the connection's raw database credentials.
Without RLS, a prompt injection or model hallucination could expose or corrupt unrelated data. With it, each agent operates within a confined scope—similar to user roles, but for autonomous systems.
Setting Up Agent Identity in Postgres
Supabase RLS uses Postgres's built-in role system. Create a dedicated role for your AI agent, then use JWT claims to dynamically set the active role for each request.
In your Supabase project, define a role like `ai_agent_user` and configure your JWT to include a `role` claim. When the agent makes a request, Supabase automatically applies that role's RLS policies.
-- Create agent role and enable RLS
CREATE ROLE ai_agent_user;
ALTER ROLE ai_agent_user SET search_path = 'public';
-- Example: agent can only insert/update rows where agent_id = current_user_id()
CREATE POLICY agent_write_policy ON tasks
FOR UPDATE
USING (agent_id = (current_setting('request.jwt.claims')::jsonb->>'sub'))
WITH CHECK (agent_id = (current_setting('request.jwt.claims')::jsonb->>'sub'));Connecting Claude to Supabase via Next.js
Use a Next.js API route as a proxy. The route validates the agent request, generates a scoped Supabase client with the agent's JWT, and hands off database operations to Claude via the Anthropic SDK.
This keeps your `SUPABASE_SERVICE_ROLE_KEY` server-only and ensures Claude operates under agent-specific RLS constraints, not unrestricted admin access.
Practical Policy Examples
A task-management agent might have RLS policies that restrict writes to tasks where `agent_id` matches the agent's identity. A document indexing agent could only insert rows into an `indexed_docs` table if the `owner_id` matches.
The key is defining the scope in your policy's `USING` and `WITH CHECK` clauses. Keep policies simple and auditable—complex logic belongs in application code, not Postgres.
Debugging RLS Policy Issues
When an agent's write fails silently, check whether the JWT claim is correctly included in the request. Use Supabase's dashboard to inspect the role and policy definitions, then test manually with `psql` using the agent role.
Enable query logging in Postgres to see exactly which policies are blocking requests. Most issues stem from mismatched claim names or incorrect policy conditions.
Open-source Implementation
The Pantheon repository at github.com/lewisallena17/pantheon demonstrates a production-ready setup: a Next.js app with Claude agent integration, Supabase RLS policies pre-configured, and TypeScript utilities for token generation and role management.
Clone it to see how agents authenticate, how policies are structured, and how to test the full flow locally.
Open-source implementation
Everything in this article runs in pantheon — a production-ready Next.js + Supabase + Claude starter. Clone it, deploy to Vercel, run PM2. The dashboard auto-commits every agent edit and reverts itself if TypeScript breaks.
◈ Tools mentioned
- Supabase — open-source Firebase alt
- Vercel — zero-config Next.js hosting
- Anthropic — Claude API
- Claude — AI assistant by Anthropic
- Gumroad — sell digital products
Some links may pay us a referral if you sign up. Never affects the price you pay.
Get the full starter kit
Lock down your AI agent database writes with Supabase RLS policies—get started with the Pantheon starter kit today.