---
title: "Cerbos"
description: "Use Cerbos policies for MainSDK access with role and attribute rules - setup, main.yaml, testing, limits and swapping."
section: "integrations"
canonical: "https://mainsdk.dev/docs/integrations/cerbos"
updated: "2026-10-28"
---

# Cerbos

> Use Cerbos policies for MainSDK access with role and attribute rules - setup, main.yaml, testing, limits and swapping.

Canonical: https://mainsdk.dev/docs/integrations/cerbos · Updated: 2026-10-28

Cerbos is an open-source authorization engine that evaluates role and attribute rules written as YAML policies. Behind [`access`](https://mainsdk.dev/docs/interfaces/access), your Cerbos policies run in place and MainSDK adds typed checks, fail-closed behaviour and audit. Pick it when your team already keeps Cerbos policies, or wants role and attribute rules managed by a dedicated policy service.

## Interfaces it serves

### Permissions (`access`)

- Status: Building for 0.3 · ships as a stable API
- Driver: `cerbos` (Cerbos)
- Docs: https://mainsdk.dev/docs/interfaces/access.md

```yaml
access:
  driver: cerbos
```

Swap to another provider: `cedar`, `opa`, `openfga`, `spicedb`, `permit`, `oso`, `avp`.

## Before you start

1. **Run a Cerbos policy decision point** your app can reach.
2. **Write your resource and role policies** and load them into Cerbos.

## Configure

```yaml title="main.yaml"
access:
  driver: cerbos
  models: [rbac, abac]
  unreachable: { deny: true, cache: 30s }
  # [TBD] connection keys for the Cerbos endpoint
```

## Use it

```ts title="lib/orders.ts"
import { access } from "mainsdk";

const decision = await access.check({ subject: user, action: "orders.approve", resource: order, context: { ip } });
if (!decision.allow) throw new Error("forbidden");
```

## Local development and testing

Build on in-process Cedar with `mainsdk dev`, or run Cerbos locally. `createTestApp()` from `@mainsdk/testing` puts `access` on its fake, and `chaos.on("access", { outage: true })` shows checks denying with `MAIN-ACCESS-0007`.

## What MainSDK adds on top

- Deny by default, with no bypass path.
- Denies when Cerbos is unreachable, with only a short cache you set.
- Lists filtered at the database, not after fetching rows.
- Every decision written to the audit log with the policy version.

See [Permissions](https://mainsdk.dev/docs/interfaces/access).

## Limits and notes

- The Cerbos driver is a phase 1 ticket in the `access` spec (milestone 0.3), next to OPA.
- Existing Cerbos policies run in place (`byo-policy`).
- A capability the driver's profile lacks, such as relations, fails `mainsdk check` with `MAIN-ACCESS-0004`.
- `access.raw()` returns the Cerbos client; `mainsdk check` lists every use.

## Swap to or from it

```yaml title="main.yaml"
access:
  driver: cedar   # was cerbos
```

> **Warning:** Your rules live in Cerbos policy files. Swapping engines means porting them; run `mainsdk test access` on the new driver before you switch.

## FAQ

**Does Cerbos do relationship-based access?** Use an engine whose capability profile declares relations, such as OpenFGA or SpiceDB, for ReBAC; `mainsdk check` tells you if your code needs one.

## Next

- [Permissions](https://mainsdk.dev/docs/interfaces/access)
- [Open Policy Agent](https://mainsdk.dev/docs/integrations/open-policy-agent) and [Oso](https://mainsdk.dev/docs/integrations/oso)
- [Swap a driver](https://mainsdk.dev/docs/guides/swap-a-driver)
