Security best practices
Keep keys out of the browser, protect every table with row level security, secure sign-in and scan your app before you publish.
Your app runs in your visitors' browsers. Anything in the page code can be read by anyone. These practices keep your data and your keys safe.
Keep private keys off the page
Your app has two places for keys, in Settings > Lyna Cloud > Secrets:
| Scope | Visible to visitors | Use it for |
|---|---|---|
| App (.env) | Yes | Public values: the project URL, the publishable key |
| Edge Functions | No | Private keys: payment secret keys, email and AI API keys |
Code that needs a private key belongs in an edge function. The page calls the function, and only the function reads the key. See Secrets.
Publishable key or secret key
The Publishable key is safe in the browser: row level security limits what it can do. The Secret key bypasses row level security. Never put it in page code or in .env.
Protect every table with row level security
Row level security (RLS) decides, row by row, who can read and change data. Without it, anyone with your publishable key can read or change the whole table.
- Turn RLS on when you create a table, not later.
- Add a policy for each action you need: read, insert, update, delete.
- Tie rows to their owner, so people only see and change their own data.
Ask the AI in plain words:
Add row level security to the bookings table. Members can read, create and cancel only their own bookings. Anyone can read the classes table, but only admins can change it.
Then check the result in Database:
- Audit shows which tables are Protected or Unprotected, and warns when a table has RLS on but no policy.
- Advisor lists security fixes, such as a public table without row security or a policy that trusts user metadata. Choose Fix to apply one.
See Database.
Secure sign-in
In Users and auth:
- Keep email confirmation on for real users.
- Set password requirements and turn on the leaked password check.
- Offer multi-factor authentication for accounts that hold sensitive data.
- List only your real addresses in Allowed redirect URLs.
- Turn off new sign-ups if your app is invite-only.
Protect your functions
- Keep Require JWT to invoke on for functions only signed-in users may call.
- Check the input a function receives before you use it.
- For payment webhooks, verify the signature with your webhook secret before you trust the event.
Check the page code
- Treat every input as untrusted. Validate forms in the page and again in the function or the database.
- Do not render raw HTML from users. If you must, ask the AI to clean it first.
- Keep packages up to date. Ask the AI to update a package that has a known issue.
Scan before you publish
The security scan looks for leaked secrets, risky code, vulnerable packages and missing row level security. It runs in the publish review and can block publishing when it finds something serious. You can also run it any time from DevTools > Security, or ask the AI to check your project.
Checklist
- No private key in page code or
.env - RLS on for every table, with a policy for each action
- Audit shows no unprotected table
- Advisor shows no security finding
- Redirect URLs list only your addresses
- Functions that need a user require a JWT
- The security scan passes