{
  "id": 17173652,
  "title": "Per-User Logins and an Audit Trail in Supabase: Auth, RLS and Triggers, a Tamper Drill, and a Small Support Portal",
  "url": "https://urgent.news/2026/10/30/per-user-logins-and-an-audit-trail-in-supabase-auth-rls-and-triggers",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-10-30T04:19:07.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/tomozilla/per-user-logins-and-an-audit-trail-in-supabase-auth-rls-and-triggers-a-tamper-drill-and-a-small-4ndl"
  },
  "original_language": "en",
  "account": "When sharing a single login, an audit log cannot differentiate between individual users. This made the author realize the need to build an audit trail using Supabase Auth, Row Level Security (RLS) and database triggers, and attempt to break it for testing purposes. All actions were performed on a Free project on 2026-10-27, and prices were subject to change.\n\nThe system consists of two tables - support_requests (the work) and activity_log (who did what). The trigger writes the log, not the page, as the code in the page can be skipped, edited, or forged. The actor's identity comes from the login, using the auth.uid() and auth.jwt() functions, and the email inside the trigger.\n\nTo ensure tamper-proofing, the log is read-only for the API, with no insert, update or delete policies. The client cannot claim to be someone else, and the who and when are stamped on the row itself. The function `public.stamp_request()` is a security definer, which runs with the owner's rights, allowing it to write even when the caller cannot. The audit log is secured by revoking insert, update, and delete privileges on the `public.activity_log` table from the 'anon' and 'authenticated' roles.\n\nThe author created three fictional demo users, Case A with a shared login (shared-desk) used by two real people, and Case B with each person using their own login. When a shared-login scenario was tested, the audit log showed only the shared-desk@example.com email address for both users. In the case of individual logins, the activity log accurately recorded each user's actions - sato added the request, tanaka moved it to in progress, and sato marked it done.\n\nThe log cannot be tampered with as the changes are recorded with who and when they occurred. The author tried to tamper with the log as staff-sato, but all attempts were unsuccessful, resulting in 403 errors. Accessing requests without signing in was allowed, while adding a request without signing in resulted in a 401 error. The author suggests treating error hints as suggestions to check against their intent, not as commands.",
  "summary": "If your team shares one login, an audit log can't tell you who did what. I wanted to see that for myself, then build the fix with Supabase Auth, RLS and database triggers, and try to break it. Everything is from my run on 2026-10-27 on a Free project. Prices change, so every number is dated. How this was made: I wrote this with Claude's help: it drafted, and I ran every step, edited the text, and…",
  "key_points": [
    "Supabase Auth, RLS, and triggers create tamper-proof audit trail",
    "Separate tables for support requests and activity log ensure accountability",
    "Shared login scenario masks individual user actions in audit log"
  ],
  "editors_take": "Moving from shared logins to individual authentication enables precise accountability by ensuring database triggers capture unique identities that cannot be forged or bypassed by client-side code.",
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}