The API checks membership too

Even if a request slips past the page-level gate, the server refuses to resolve an account the caller isn't a member of.

What it is

getAuthedUser() is the function every authenticated route calls. It resolves the acting org by a documented precedence, then — for anyone who isn't platform-side — verifies the caller is actually a member of the org the URL asked for. Failure returns null, and callers turn null into 401 Unauthorized.

Also called: 401 unauthorized cross tenant · server-side tenant check · API isolation

See it
The API checks membership too
Area
Platform & Admin
Group
Tenancy & isolation
System
Multi-Tenancy & Identity
Solves
3 named problems
01Precedence for the acting org: impersonation target (platform-side only), then subdomain, then the user's own metadata org, then the linked session org.
02Membership is read from publicMetadata.orgId plus publicMetadata.memberships.
03The check only blocks users who HAVE memberships — someone mid-onboarding with none falls through to the onboarding flow instead of being locked out of the very endpoints that would set them up.
A request-trace panel: same API call from two accounts, one returning data, one returning 401 with the server log line naming the mismatch. Source: src/lib/serverAuth.ts. Sample data — no customer information appears here.
How it works
  1. 1Precedence for the acting org: impersonation target (platform-side only), then subdomain, then the user's own metadata org, then the linked session org.
  2. 2Membership is read from publicMetadata.orgId plus publicMetadata.memberships.
  3. 3The check only blocks users who HAVE memberships — someone mid-onboarding with none falls through to the onboarding flow instead of being locked out of the very endpoints that would set them up.
  4. 4A block is logged with the user id, the requested subdomain and their membership list.
  5. 5Non-owners with no resolvable org get null rather than a default account.
Why we built it

The comment states the failure mode and the three exemptions that must not block, in order. The exemptions are the interesting part: a brand-new user has no org yet, and blocking them here 'would prevent the very flows that set up their first orgId' — a gate that locks out new hires is a gate that gets removed. The silent default is called out separately: previously a miss returned the first account's id, which 'silently dropped other tenants' users onto [that tenant's] data when their session was missing the org claim (a frequent state on the apex host).'

The problem
  • Client-side or middleware-only enforcement can be bypassed by calling the API directly.
  • A session missing its org claim used to fall back to a real account instead of failing.
  • An over-broad membership check would strand users who haven't finished onboarding.
Sound familiar?
What you get
Direct API calls are scoped by the same rule as page loads.
A user with no resolvable account gets an honest error rather than someone else's data.
New invitees can still complete signup while the gate stays closed for everyone else.

See it on your own jobs

Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.

or keep browsing features →