Security (RLS + scopes)#
Identities on the data API#
/data/* accepts two identities:
- Project API key (
X-AFRIBASE-API-Key) - scoped to one project - Project-user JWT (
Authorization: Bearer) - issued by project auth (sign-in / OTP). This is the per-user identity RLS evaluates.
When both are present, the user JWT wins and the API key must belong to the same project.
API key scopes#
Keys are created with scopes (see Authentication). A key with any module scope is restricted to exactly those scopes; legacy keys keep full module access. Violations return 403 with an actionable message.
Row-level security (policies)#
Policies are configured per table + action (select / insert / update / delete) with a subject and effect (allow / deny).
Subject matching:
| Subject | Matches |
|---|---|
api_key | Requests authenticated with the project API key |
authenticated | Requests with a valid project-user JWT (logged-in) |
public | Both |
any | Both |
Rules:
- No policies on a table: legacy allow-all (backward compatible)
- Policies exist: a matching ALLOW is required; DENY always wins
- The classic setup is an
authenticatedALLOW per action, so only logged-in users can read/write
Example: only logged-in users can insert messages:
{ "action": "insert", "subject": "authenticated", "effect": "allow" }
JSONCross-project protection#
API keys are authorized only to their own project; requests to another project's routes return 403.
The users table#
The users table (auth users) is managed by the platform:
- Cannot be created, renamed or deleted
- Its columns cannot be added, updated or removed
- Writes over the data API return 400
- Data API reads are always scoped to the project
Secrets and env vars#
- Stored encrypted at rest
- Masked in list responses; revealed one at a time
- Scoped keys:
secrets:read/write,env:read/write