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:- Row-level security. Tables created with a
user_iduuid 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 throughresult db migrate. - Signed-in-only writes. Storage uploads reject anonymous callers.
- 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.localfor 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.