supabase-enterprise-rbac
Implement custom role-based access control via JWT claims in Supabase: app_metadata.role, RLS policies with auth.jwt() role extraction, organization-scoped access, and API key scoping. Use when implementing role-based permissions, configuring organization-level access, building admin/member/viewer hierarchies, or scoping API keys per role. Trigger: "supabase RBAC", "supabase roles", "supabase permissions", "supabase JWT claims", "supabase organization access", "supabase custom roles", "supabase app_metadata".
What this skill does
# Supabase Enterprise RBAC
## Overview
Supabase supports custom role-based access control (RBAC) by storing role information in `app_metadata` on the user's JWT, then reading those claims in RLS policies via `auth.jwt() ->> 'role'`. This skill implements a complete RBAC system: defining roles in `app_metadata`, writing RLS policies that enforce role hierarchies, scoping access by organization, managing roles through the Admin API, and protecting API endpoints with role checks — all using real `createClient` from `@supabase/supabase-js`.
**When to use:** Building multi-role applications (admin/editor/viewer), implementing organization-scoped access, creating custom permission systems beyond Supabase's built-in `anon`/`authenticated` roles, or scoping API operations by user role.
## Prerequisites
- `@supabase/supabase-js` v2+ with service role key for admin operations
- Understanding of JWT claims and Supabase's `auth.jwt()` SQL function
- Database access via SQL Editor or `psql` for RLS policy creation
- Supabase project with authentication configured
## Instructions
### Step 1: Define Roles via app_metadata and JWT Claims
Store custom roles in the user's `app_metadata` using the Admin API. These claims appear in every JWT the user receives and are available in RLS policies.
**Set user roles with the Admin API:**
```typescript
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!,
{ auth: { autoRefreshToken: false, persistSession: false } }
);
// Define the role hierarchy
type AppRole = 'admin' | 'editor' | 'viewer' | 'member';
interface AppMetadata {
role: AppRole;
org_id: string;
permissions?: string[];
}
// Assign a role to a user (admin operation)
async function setUserRole(userId: string, role: AppRole, orgId: string) {
const { data, error } = await supabase.auth.admin.updateUserById(userId, {
app_metadata: {
role,
org_id: orgId,
},
});
if (error) throw new Error(`Failed to set role: ${error.message}`);
console.log(`User ${userId} assigned role "${role}" in org "${orgId}"`);
return data.user;
}
// Assign granular permissions (optional, for fine-grained control)
async function setUserPermissions(
userId: string,
permissions: string[]
) {
const { data, error } = await supabase.auth.admin.updateUserById(userId, {
app_metadata: { permissions },
});
if (error) throw new Error(`Failed to set permissions: ${error.message}`);
return data.user;
}
// Bulk role assignment (e.g., onboarding a team)
async function assignTeamRoles(
orgId: string,
assignments: { userId: string; role: AppRole }[]
) {
const results = await Promise.allSettled(
assignments.map(({ userId, role }) => setUserRole(userId, role, orgId))
);
const succeeded = results.filter((r) => r.status === 'fulfilled').length;
const failed = results.filter((r) => r.status === 'rejected').length;
console.log(`Assigned ${succeeded} roles, ${failed} failures`);
}
```
**Read roles from the JWT in application code:**
```typescript
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
// Get the current user's role from their JWT
async function getCurrentUserRole(): Promise<AppRole | null> {
const { data: { user }, error } = await supabase.auth.getUser();
if (error || !user) return null;
return (user.app_metadata?.role as AppRole) ?? null;
}
// Get the current user's organization
async function getCurrentOrg(): Promise<string | null> {
const { data: { user } } = await supabase.auth.getUser();
return user?.app_metadata?.org_id ?? null;
}
// Check if current user has a specific role or higher
function hasRole(userRole: AppRole, requiredRole: AppRole): boolean {
const hierarchy: Record<AppRole, number> = {
admin: 4,
editor: 3,
member: 2,
viewer: 1,
};
return hierarchy[userRole] >= hierarchy[requiredRole];
}
// Middleware-style role check for API routes
async function requireRole(requiredRole: AppRole) {
const role = await getCurrentUserRole();
if (!role || !hasRole(role, requiredRole)) {
throw new Error(
`Access denied: requires "${requiredRole}" role, user has "${role ?? 'none'}"`
);
}
}
```
### Step 2: RLS Policies with JWT Role Claims
Write Row Level Security policies that read `auth.jwt() ->> 'role'` and `auth.jwt() -> 'app_metadata' ->> 'org_id'` to enforce role-based and organization-scoped access.
**Role-based RLS policies:**
```sql
-- Create a helper function to extract role from JWT
CREATE OR REPLACE FUNCTION public.get_user_role()
RETURNS text AS $$
SELECT coalesce(
auth.jwt() -> 'app_metadata' ->> 'role',
'viewer' -- default role if not set
);
$$ LANGUAGE sql STABLE SECURITY DEFINER;
-- Create a helper function to extract org_id from JWT
CREATE OR REPLACE FUNCTION public.get_user_org_id()
RETURNS text AS $$
SELECT auth.jwt() -> 'app_metadata' ->> 'org_id';
$$ LANGUAGE sql STABLE SECURITY DEFINER;
-- Enable RLS on all tables
ALTER TABLE public.projects ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.documents ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.team_members ENABLE ROW LEVEL SECURITY;
-- Projects: org members can read, editors+ can create/update, admins can delete
CREATE POLICY "org_members_read_projects" ON public.projects
FOR SELECT USING (
org_id = get_user_org_id()
);
CREATE POLICY "editors_create_projects" ON public.projects
FOR INSERT WITH CHECK (
org_id = get_user_org_id()
AND get_user_role() IN ('admin', 'editor')
);
CREATE POLICY "editors_update_projects" ON public.projects
FOR UPDATE USING (
org_id = get_user_org_id()
AND get_user_role() IN ('admin', 'editor')
);
CREATE POLICY "admins_delete_projects" ON public.projects
FOR DELETE USING (
org_id = get_user_org_id()
AND get_user_role() = 'admin'
);
-- Documents: org-scoped with role-based write access
CREATE POLICY "org_read_documents" ON public.documents
FOR SELECT USING (
org_id = get_user_org_id()
);
CREATE POLICY "editors_write_documents" ON public.documents
FOR INSERT WITH CHECK (
org_id = get_user_org_id()
AND get_user_role() IN ('admin', 'editor')
);
CREATE POLICY "owner_or_admin_update_documents" ON public.documents
FOR UPDATE USING (
org_id = get_user_org_id()
AND (
created_by = auth.uid()
OR get_user_role() = 'admin'
)
);
-- Team members: admins manage team, members can read
CREATE POLICY "org_read_team" ON public.team_members
FOR SELECT USING (
org_id = get_user_org_id()
);
CREATE POLICY "admins_manage_team" ON public.team_members
FOR ALL USING (
org_id = get_user_org_id()
AND get_user_role() = 'admin'
);
```
**Organization-scoped access table schema:**
```sql
-- Organizations table
CREATE TABLE public.organizations (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
name text NOT NULL,
slug text UNIQUE NOT NULL,
created_at timestamptz DEFAULT now()
);
-- Team members junction table
CREATE TABLE public.team_members (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
org_id uuid REFERENCES public.organizations(id) ON DELETE CASCADE,
user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE,
role text NOT NULL DEFAULT 'member' CHECK (role IN ('admin', 'editor', 'member', 'viewer')),
invited_by uuid REFERENCES auth.users(id),
created_at timestamptz DEFAULT now(),
UNIQUE(org_id, user_id)
);
-- Projects scoped to organizations
CREATE TABLE public.projects (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
org_id uuid REFERENCES public.organizations(id) ON DELETE CASCADE,
name text NOT NULL,
created_by uuid REFERENCES auth.users(id),
created_at timestamptz DEFAULT now()
);
-- Index for fast org-scoped queries
CREATE INDEX idx_team_members_org ON public.team_members(org_id);
CREATE INRelated in Backend & APIs
jfrog
IncludedInteract with the JFrog Platform via the JFrog CLI and REST/GraphQL APIs. Use this skill when the user wants to manage Artifactory repositories, upload or download artifacts, manage builds, configure permissions, manage users and groups, work with access tokens, configure JFrog CLI servers, search artifacts, manage properties, set up replication, manage JFrog Projects, run security audits or scans, look up CVE details, query exposures scan results from JFrog Advanced Security, manage release bundles and lifecycle operations, aggregate or export platform data, or perform any JFrog Platform administration task. Also use when the user mentions jf, jfrog, artifactory, xray, distribution, evidence, apptrust, onemodel, graphql, workers, mission control, curation, advanced security, exposures, or any JFrog product name.
cupynumeric-migration-readiness
IncludedPre-migration readiness assessor for porting NumPy to cuPyNumeric. Use BEFORE substantial porting work begins when the user asks whether code will scale on GPU, whether they should migrate to cuPyNumeric, which NumPy patterns transfer cleanly, what must be refactored before porting, or mentions pre-port assessment, scaling analysis, or refactor planning. Inspect the user's source code, look up NumPy usage, cross-reference the cuPyNumeric API support manifest, and distinguish distributed-scaling-friendly patterns from blockers such as unsupported APIs, scalar synchronization, host round-trips, Python/object-heavy control flow, shape/data-dependent branching, and in-place mutation hazards. Produce a verdict of READY, LIGHT REFACTOR, SIGNIFICANT REFACTOR, or NOT RECOMMENDED, with concrete refactor pointers.
alibabacloud-data-agent-skill
IncludedInvoke Alibaba Cloud Apsara Data Agent for Analytics via CLI to perform natural language-driven data analysis on enterprise databases. Data Agent for Analytics is an intelligent data analysis agent developed by Alibaba Cloud Database team for enterprise users. It automatically completes requirement analysis, data understanding, analysis insights, and report generation based on natural language descriptions. This tool supports: discovering data resources (instances/databases/tables) managed in DMS, initiating query or deep analysis sessions, real-time progress tracking, and retrieving analysis conclusions and generated reports. Use this Skill when users need to query databases, analyze data trends, generate data reports, ask questions in natural language, or mention "Data Agent", "data analysis", "database query", "SQL analysis", "data insights".
token-optimizer
IncludedReduce OpenClaw token usage and API costs through smart model routing, heartbeat optimization, budget tracking, and native 2026.2.15 features (session pruning, bootstrap size limits, cache TTL alignment). Use when token costs are high, API rate limits are being hit, or hosting multiple agents at scale. The 4 executable scripts (context_optimizer, model_router, heartbeat_optimizer, token_tracker) are local-only — no network requests, no subprocess calls, no system modifications. Reference files (PROVIDERS.md, config-patches.json) document optional multi-provider strategies that require external API keys and network access if you choose to use them. See SECURITY.md for full breakdown.
resend-cli
IncludedUse this skill when the task is specifically about operating Resend from an AI agent, terminal session, or CI job via the official resend CLI: installing/authenticating the CLI, sending/listing/updating/cancelling emails, batch sends, domains and DNS, webhooks and local listeners, inbound receiving, contacts, topics, segments, broadcasts, templates, API keys, profiles, or debugging Resend CLI/API failures. Trigger on mentions of Resend CLI, `resend`, `resend doctor`, `resend emails send`, `resend domains`, `resend webhooks listen`, `resend emails receiving`, or agent-friendly terminal automation.
alibabacloud-odps-maxframe-coding
IncludedUse this skill for MaxFrame SDK development and documentation navigation on Alibaba Cloud MaxCompute (ODPS). Helps answer MaxFrame API, concept, official example, and supported pandas API questions; create data processing programs; read/write MaxCompute tables; debug jobs (remote or local); and build custom DPE runtime images. Trigger when users mention MaxFrame, MaxCompute with MaxFrame, ODPS table processing, DPE runtime, MaxFrame docs/examples, DataFrame/Tensor operations, or GPU runtime setup. Works for both English and Chinese queries about Alibaba Cloud data processing with MaxFrame.