Step 12: Configure Row-Level Security

Phase: implement

Context

You have project_id, service_key, and tables_created. Now set up access rules so the right people can see the right data.

What to do

Apply Row-Level Security (RLS) policies to your tables. This controls who can read and write data when using the anon_key (client-side).

Available RLS templates

TemplateWho can readWho can writeUse when
public_read Everyone No one (admin only via service_key) Reference data, shared content that users shouldn't modify
public_read_write Everyone Everyone Open collaboration (voting, public comments, shared lists without auth)
user_owns_rows Only the row owner Only the row owner Personal data (my tasks, my profile, my scores). Requires owner_column.

Apply RLS

POST https://run402.com/admin/v1/projects/{project_id}/rls
Content-Type: application/json
Authorization: Bearer {service_key}

{
  "template": "user_owns_rows",
  "tables": [
    {"table": "todos", "owner_column": "user_id"},
    {"table": "profiles", "owner_column": "id"}
  ]
}

Response:

{
  "status": "ok",
  "template": "user_owns_rows",
  "tables": ["todos", "profiles"]
}

Multiple templates

You can apply different templates to different tables. Make separate API calls for each template:

  1. Apply user_owns_rows to personal data tables
  2. Apply public_read to shared reference data tables
  3. Apply public_read_write to open collaboration tables

Decision guide

  • App has auth? Use user_owns_rows for personal data, public_read for shared data.
  • App has no auth? Use public_read_write for everything. Anyone with the link can read and write.
  • Mixed: Some tables public_read (everyone sees), some user_owns_rows (personal data).

Important notes

  • The service_key always bypasses RLS. Use it only for admin setup, never in frontend code.
  • The anon_key respects RLS. This is what goes in the frontend code.
  • For user_owns_rows, the owner_column must contain the user's UUID (from auth). The column must exist in the table.

What to tell the user

"I've set up the access rules for your app. [Everyone can see everything / Each person can only see their own stuff / Some things are shared, some are private]."

Expected output

  • rls_configured — Map of table → RLS template applied:
    {
      "todos": "user_owns_rows",
      "categories": "public_read"
    }

Memory directive