User profile reads/writes routed through backend API instead of Supabase direct

marklok replaces direct Supabase queries in `UserProfileContext.tsx` with `GET` and `PATCH /user/profile` backend endpoints. The PATCH handler adds an explicit column allowlist, narrowing what the browser can touch compared to the previous RLS-only approach.

securityinfrastructure

The new GET /user/profile returns the calling user's row from user_profiles. PATCH /user/profile accepts only fields on an explicit allowlist: display_name, organisation, tabular_model, claude_api_key, gemini_api_key, message_credits_used, credits_reset_date. Anything else is silently dropped. That's a security improvement over the old pattern, where the browser wrote directly to Supabase and RLS was the only guard.

Two things to examine before adopting. The allowlist includes claude_api_key and gemini_api_key, meaning API keys transit as request body through the backend. The diff shows no log-redaction, so those values could end up in server logs. message_credits_used is also client-writable through the same endpoint, which lets a client manipulate their own credit count unless something downstream (RLS, triggers) prevents it - nothing in this diff shows that protection.

The context-side changes are mechanical. 215 lines removed, 137 added. mapProfileRow, getAccessToken, and apiFetch are extracted as module-level helpers, and the credit-reset math moves into mapProfileRow where it's easier to read than the old inline version.

The pattern here fits a broader architectural direction: moving Supabase-direct browser access behind the backend, probably for audit logging, validation, and eventual multi-tenant use. Worth watching whether marklok does the same for other tables.

So what Worth pulling if you're centralizing backend access for auth or audit reasons. The allowlist approach is cleaner than relying on RLS alone. Review the `claude_api_key` and `message_credits_used` entries before deploying - either tighten the allowlist or add log scrubbing depending on your threat model.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

1 commit from marklok/danishmike, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
a0f72526 Refactor user profile to use backend API Markus 2026-05-08 ↗ GitHub
- Add GET and PATCH /user/profile endpoints
- Update UserProfileProvider to fetch/update profile via API
  instead of querying Supabase directly from the frontend

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-207.md from inside the repo you want the changes in.

⬇ Download capture-thread-207.md