Skip to main content
Three credentials, three rules:

The publishable key is public - plan for it

Anyone can read it out of your shipped frontend. That is by design. What protects your data:
  1. Row-level security. Tables created with a user_id uuid column get an owner policy that scopes rows to the signed-in user. Keep RLS on (the default) for any per-user data; custom access rules run as policy SQL through result db migrate.
  2. Signed-in-only writes. Storage uploads reject anonymous callers.
  3. Functions as the trust boundary. AI calls and email sends work with the publishable key - anyone holding it can drive spend. Put expensive or sensitive operations in a serverless function.

The admin key is never public

  • Never in client code, never in NEXT_PUBLIC_* vars, never in the browser.
  • It belongs in .env.local for the CLI, or server-side code only.
  • Everything the CLI does (schema, buckets, secrets) uses it - that’s why setup is a terminal activity.

Where the session lives

The access token is held in memory. The refresh token that keeps someone signed in across reloads is a first-party cookie on your own origin, written by the SDK, which means JavaScript running on your site can read it: an XSS hole is a session-theft hole. Sanitize anything you render as HTML and keep third-party scripts off pages that matter. The alternative is @resultdev/sdk/ssr, where the refresh token is an httpOnly cookie your own server writes and browser JavaScript cannot touch. It costs a refresh route and a server client, and it is the right trade for apps holding something worth stealing.