# Security & Access Control

> Row-level security and physical tenant scoping, enforced on every surface.

Resources opt into row-level security declaratively. The rules are compiled into the manifest and enforced in `rastack-api-core` on every surface — server, browser, and admin alike.

```ts title="resources/notes.ts"
export const Note = resource("notes", "note", {
  title: s.string({ maxLength: 120 }),
  body: s.string(),
}, {
  access: {
    ownerField: "owner",     // stamp + filter by the caller
    scope: "owner",          // physically partition the table
    adminGroups: ["staff"],  // groups that bypass the row filter
  },
});
```

## What the access config does

| Setting | Effect |
| --- | --- |
| `ownerField` | stamps the owner on write, filters lists, and returns 404 on cross-identity access |
| `scope: "owner"` | physically partitions the table under `warehouse/tenants/{sub}/…` |
| `adminGroups` | groups whose members bypass the row filter |

## Partitioned all the way down

The model is one idea applied at every layer: **data is partitioned by identity all the way down**. The same verified Cognito `sub` keys the S3 prefix, the API row filter, and the device cache namespace.

- **S3 key prefix** — the Cognito Identity Pool role fences `tenants/{sub}/` with the `${cognito-identity.amazonaws.com:sub}` IAM policy variable.
- **API row filter** — `rastack-api-core` filters every list and returns 404 on cross-identity reads.
- **Device cache namespace** — local data is namespaced per identity; revoked access deletes it.

> **Note:** Because the same `rastack-api-core` runs in the browser, a client cannot escape these rules by talking to the WASM engine directly — the engine enforces them too.

---

_Source: [https://reactapistack.com/docs/security](https://reactapistack.com/docs/security) · Full docs as one file: [llms-full.txt](https://reactapistack.com/llms-full.txt)_
