# Descope Fga Schema

> Author, edit, or apply a Descope FGA schema using the ReBAC/ABAC DSL. Use this skill whenever the user asks to create a new FGA schema, modify an existing one, add types/relations/permissions/conditions, review an authorization model, or apply schema changes to a Descope project. Trigger even if the user says things like "set up authorization", "define roles and permissions", "add team-based acce…

- **Type:** Skill
- **Install:** `agentstack add skill-descope-skills-descope-fga-schema`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [descope](https://agentstack.voostack.com/s/descope)
- **Installs:** 0
- **Category:** [Security](https://agentstack.voostack.com/c/security)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [descope](https://github.com/descope)
- **Source:** https://github.com/descope/skills/tree/main/skills/descope-fga-schema

## Install

```sh
agentstack add skill-descope-skills-descope-fga-schema
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# FGA DSL Authoring

Help the user design and apply Descope FGA schemas. The workflow is: understand the requirement → draft the DSL → validate via dry run → show the user + any data loss warnings → get confirmation → apply.

## MCP Setup — check first, stop if missing

**Before doing anything else**, check whether the Descope Management MCP is connected by looking for tools whose names contain `FGASchema` or `DryRunSchema` (e.g. `mcp__descope__DryRunSchema`). The exact prefix depends on how the user installed the MCP, but the operation IDs are `DryRunSchema`, `CreateFGASchema`, and `GetFGASchema`.

**If the tools are not found:** output only the message below, then end your turn. Do not generate a schema, do not say "here's what I'll apply once connected", do not do any design work, do not continue:

> The Descope Management MCP is required. If not yet installed, install and authorize it, then restart Claude Code and re-run `/descope-fga-schema`.
> If already installed, it may need authorization. Authorize the Descope MCP, then restart Claude Code and re-run `/descope-fga-schema`.

**If the tools are found:** call `GetFGASchema` immediately as a connectivity probe before doing any other work. If this call returns an authorization error, output only the message below and end your turn:

> The Descope MCP is installed but not authorized. Authorize it, restart Claude Code, and re-run `/descope-fga-schema`.

All FGA operations go through MCP tool calls — never make raw HTTP requests yourself.

Once connected, use the `GetFGASchema` tool to read the current schema before editing — always do this when the user asks to modify an existing schema.

## Grammar

Every schema begins with exactly:
```
model AuthZ 1.0
```
No other name or version is accepted by the API.

Full structure:
```
model AuthZ 1.0

[constraint [:][(args...)]]*
[condition () {  }]*

type 
  [relation :  [| ]* [with ]]*
  [permission :  [with ]]*
```

Keywords: `model` `type` `relation` `permission` `condition` `constraint` `with`

Operators:
- Permission expr: `|` union, `&` intersect, `-` subtract. Mix operators with parens: `a | (b - c)`
- Set arrow: `relation.permission` — walks a stored relation to reach the subject's own permissions (e.g. `parent.can_view`)
- Target set: `Type#relation` — see dedicated section below
- `with` clause (relations and permissions): `&` AND, `|` OR, `!` NOT, parens: `with A & (B | !C)`. Conditions are evaluated at **check time** — `with` gates whether the relation or permission counts during evaluation. Only one `with` clause is allowed per relation or permission definition — combine multiple conditions inside it with `&`/`|`/`!`.

**No comments** — the DSL parser has no comment token.

Naming: **PascalCase** for Types, Conditions, Constraints. **snake_case** for relations and permissions.

## Target Set Pattern (`Type#relation`)

When a relation should be held by members of a group (e.g. "any member of this Team"), put `Type#relation` directly in the relation definition. This stores individual member subjects — the right granularity for permission checks.

The indirect way — storing the group itself and deriving membership via a permission — produces correct relation expansion, but it introduces a `contributor_team` relation with no semantic meaning of its own. The only meaningful entity is the individual member. The target set syntax is more concise and directly expresses the intent.

**Avoid (extra relation with no semantic value):**
```
type Repository
  relation contributor_team: Team
  permission contributor: contributor_team.member
```

**Prefer (concise, direct):**
```
type Repository
  relation contributor: Team#member
```

You can mix direct subjects with target set subjects: `relation editor: User | Team#member`

## ABAC Anti-Patterns to Avoid

### Never use a "blocked" relation + subtraction to express a condition

`with` conditions are evaluated at **check time** — when a permission check is made against the context passed in the request. Relations are always stored unconditionally; the condition only affects whether the relation counts during permission evaluation.

The `blocked` relation + subtraction pattern is wrong because it requires manually maintaining a separate set of `blocked` edges in the DB for every excluded user. It's the wrong tool: use `with !Condition` on the relation that grants access instead — it is evaluated automatically at check time with no extra stored relations.

```
// NEVER do this — requires maintaining a separate "blocked" edge per user in the DB
relation creator: User
relation blocked: User with NorthKorea
permission can_delete: creator - blocked

// Right — condition evaluated automatically at check time; no extra edges
relation creator: User with !NorthKorea
permission can_delete: creator
```

### Don't write custom CEL when a built-in constraint covers it

A custom `condition` that checks a numeric range is just reinventing `NumRange` (or `NumAtLeast`/`NumAtMost`). Built-in constraints are more concise, less error-prone, and form a common vocabulary that makes schemas easier for both humans and agents to read and reason about. Use them.

**Wrong:**
```
condition DuringBusinessHours(seconds_since_midnight int) { seconds_since_midnight >= 32400 && seconds_since_midnight  **Warning: applying this schema will permanently delete all stored relations of these types:**
> - `folder#viewer`
> - `doc#editor`
>
> This cannot be undone. Confirm to proceed.

If `hasDeletes` is false, just show the schema and ask for confirmation.

### Step 3 — Get confirmation

End your turn after Step 2. Do not call `CreateFGASchema` in the same turn as `DryRunSchema` — the user must see the schema and any deletion warnings before you proceed. Wait for the user to reply with explicit approval ("yes", "apply", "go ahead", etc.).

### Step 4 — Apply

Before calling `CreateFGASchema`, verify all three of the following are true:
- You showed the full DSL in a code block in a prior turn (not in this turn)
- You surfaced all deletion warnings from the dry-run response (or confirmed `hasDeletes` was false)
- The user's most recent message is an explicit approval in response to your confirmation prompt

If any of these are not true, do not call `CreateFGASchema`. Go back to Step 2 instead.

When all three are confirmed, call `CreateFGASchema` with the same DSL from the dry run. Confirm success to the user.

The reason this gate matters: `CreateFGASchema` is irreversible. Relation tuples deleted by a schema change cannot be recovered. Skipping confirmation is never safe, even when the change looks minor.

## Examples

### Basic ReBAC with hierarchy

```
model AuthZ 1.0

type User

type Folder

type Doc
  relation owner: User
  relation parent: Folder
  permission can_view: owner | parent.owner
  permission can_edit: owner
```

### Group membership via target set

```
model AuthZ 1.0

type User

type Team
  relation member: User

type Repository
  relation owner: User
  relation contributor: User | Team#member
  permission can_push: owner | contributor
  permission can_read: can_push
```

### ABAC: time-gated access

```
model AuthZ 1.0

constraint ShiftHours:NumRange

type User

type PatientRecord
  relation viewer: User with ShiftHours
  relation owner: User
  permission can_view: viewer | owner
```

### Reused constraint kind with aliases — and `with` on a permission

```
model AuthZ 1.0

constraint FiveEyes:GeoCountry("US","GB","CA","AU","NZ")
constraint Sanction:GeoCountry("KP","IR","SY","RU")
constraint OfficeOnly:IpRange("10.0.0.0/8")

type User

type Resource
  relation allowed: User with FiveEyes & !Sanction
  relation owner: User
  permission can_access: allowed
  permission can_delete: owner with OfficeOnly
```

`allowed` carries geo-gating on the relation — it applies to every permission that uses `allowed`. `can_delete` uses `with` on the permission itself so the IP restriction scopes only deletion, not access.

### Nested permissions with `with` — conditions stack

```
model AuthZ 1.0

constraint BusinessHours:NumRange(32400, 61200)
constraint OfficeNetwork:IpRange("10.0.0.0/8")

type User

type Document
  relation reader: User
  permission can_read: reader with BusinessHours
  permission can_edit: can_read with OfficeNetwork
```

`can_edit` requires both `BusinessHours` (from `can_read`) **and** `OfficeNetwork` (from `can_edit`'s own `with`). Both conditions must be true at check time — `with` clauses on nested permissions accumulate.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [descope](https://github.com/descope)
- **Source:** [descope/skills](https://github.com/descope/skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-descope-skills-descope-fga-schema
- Seller: https://agentstack.voostack.com/s/descope
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
