Skip to content
Sleep at nightData foundation

Login & permissions

Nobody sees data that isn't theirs. Ever.

Login is done for you, and it's done right. The server decides who each user is and what they can touch. The browser never gets a vote, and if anything looks off, the door stays locked.

  • 1

    path that decides who a user is

  • 4

    roles, compared in one place

  • 0

    company IDs accepted from the browser

The problem this solves

Without a shared foundation, every team rebuilds these edge cases — differently.

The leak you find out about from a customer

One endpoint trusts an ID sent from the browser. One curious user edits it. Now they're reading another company's data, and you're writing the apology email. Here, the browser never gets to pick the tenant. The server does.

Role rules that drift

Every feature writes its own role check. Over time they disagree. An admin-only action in one screen quietly becomes open to editors in another, and nobody notices until an audit does.

The 'who can see this?' mess

Company-wide members, project-only members, and owners all overlap. Without one rule, every endpoint answers 'who can see this project?' a little differently. That's how weird access bugs are born.

How it works

The mechanism end to end, as implemented in the repository.

  1. 1

    Clerk checks the login

    Clerk confirms the session once per request. No session means the request stops right there.

  2. 2

    The login maps to a real user

    The server looks the login up in your own users table. An account that isn't set up yet gets a clear error, not a free pass.

  3. 3

    Access is checked next to the write

    The same database call that saves your data also confirms the user belongs there. There's no gap for a mistake to slip through.

  4. 4

    One rule decides roles

    Viewer, editor, admin, owner. One comparison function ranks them, and every feature uses it. Company and project access merge with a single rule.

Interactive example

See it working

This walkthrough demonstrates the implemented backend contract without using an account, credentials, or provider calls.

Interactive example

Explore the implemented decisions

Choose a sample state
Read access

Deterministic sample data only. No account, provider, or network connection is used by the interaction.

Highlights

Why it matters

The server decides who you are

Every request is checked against a real user in your database. What the browser claims doesn't matter.

One rule for roles

Viewer, editor, admin, owner. One ordering, used everywhere, so access never drifts between features.

Locked by default

Missing login, unknown account, or no membership? The request stops with a clear error. Nothing slips through on a lucky default.

Engineering guarantees

What this does and does not promise

Safety boundary

Clerk's uptime and your production security review are still yours to own. This kit proves the server-side boundary, which is the part most teams get wrong.

Implementation evidence

The boundary above is code, not a claim. These files carry the contract:

  • src/server/auth.ts
  • src/server/permissions.ts
  • src/policies/roles.ts
Questions

Frequently asked questions

Build on the login & permissions foundation

The docs describe the same contracts this page demonstrates.