---
title: "Access reviews"
---

# Access reviews

Run access review campaigns in Neural Inverse Govern on a schedule or ad hoc, decide keep or revoke for every binding, and export the evidence.

An access review campaign asks named reviewers to confirm or remove every role binding in a part of the organisation. The result is evidence of periodic access certification, which auditors ask for under frameworks such as SOC 2 and ISO 27001. Govern produces the evidence toward those controls; certification remains with your auditor.

Access reviews work through the API. They have no console page yet.

## How a campaign works

1. A campaign covers the bindings of one role, on one node and, by default, its subtree. When it opens, it snapshots those bindings as items.
2. Reviewers decide each item: `keep` or `revoke`, with a justification. A revoke decision revokes the binding in the same transaction.
3. A reviewer cannot decide an item about their own access.
4. When the campaign closes with `auto_revoke` on, undecided items are revoked, except the binding of a node's last administrator.
5. The evidence export lists every item, decision, reviewer, time and the audit record ids.

Reviewers are the principals you name, or by default the holders of `iam.reviews:decide` on the item's node.

## Schedule campaigns

```bash
curl -sS -X POST "$KEYSTONE_URL/api/v1/access/review-schedules" \
  -H "Authorization: Bearer $ADMIN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"name": "Quarterly production admins", "node_id": "'$PROD_NODE'", "role_id": "'$ROLE_ID'",
       "include_subtree": true, "duration_days": 14, "auto_revoke": true,
       "frequency_days": 90, "enabled": true, "first_run_at": "2026-11-01T09:00:00Z"}'
```

| Field | Meaning |
|---|---|
| `name` | Campaign name |
| `node_id`, `role_id` | The bindings in scope |
| `include_subtree` | Default `true` |
| `duration_days` | 1 to 90 |
| `reviewers` | Principals who decide; empty means holders of `iam.reviews:decide` on the node |
| `auto_revoke` | Revoke undecided items when the campaign closes |
| `frequency_days`, `enabled`, `first_run_at` | Schedules only |

Schedules and campaign expiry are processed every 5 minutes. To open one campaign now, `POST /api/v1/access/reviews` with the campaign fields.

## Decide items

```bash
curl -sS "$KEYSTONE_URL/api/v1/access/reviews/$REVIEW_ID/items" \
  -H "Authorization: Bearer $REVIEWER_TOKEN"

curl -sS -X POST "$KEYSTONE_URL/api/v1/access/reviews/$REVIEW_ID/items/$ITEM_ID/decision" \
  -H "Authorization: Bearer $REVIEWER_TOKEN" -H 'Content-Type: application/json' \
  -d '{"decision": "revoke", "justification": "Moved to another team in September"}'
```

A revoke needs a justification.

## Export evidence

`GET /api/v1/access/reviews/{id}/evidence?format=json` (the default) or `format=csv`. Exports need `iam.reviews:export`.

## Routes

| Route | Permission |
|---|---|
| `GET`, `POST /api/v1/access/review-schedules`; `GET`, `PUT`, `DELETE /api/v1/access/review-schedules/{id}` | `iam.reviews:read`, `iam.reviews:manage` |
| `GET /api/v1/access/reviews` (query `state`) | `iam.reviews:read` |
| `POST /api/v1/access/reviews` | `iam.reviews:manage` |
| `GET /api/v1/access/reviews/{id}` | `iam.reviews:read` |
| `POST /api/v1/access/reviews/{id}/close` | `iam.reviews:manage` |
| `GET /api/v1/access/reviews/{id}/items` (query `outcome`) | `iam.reviews:read` |
| `POST /api/v1/access/reviews/{id}/items/{item_id}/decision` | A named reviewer, or `iam.reviews:decide` on the item's node; never one's own access |
| `GET /api/v1/access/reviews/{id}/evidence` | `iam.reviews:export` |

The Security and compliance account role holds `iam.reviews:manage` and `iam.reviews:decide`. The auditor role can read and export reviews but not decide.

## Scope

Campaigns review role bindings on directory nodes. The design extends reviews to resource shares, API keys and service accounts; that extension is not described in the built routes, so do not rely on it.

## Related

- Unused access is also removed by the inactivity setting (`inactivity_disable_days`) on [Access guardrails](https://neuralinverse.com/docs/govern/access-guardrails/#access-settings).
- SCIM deactivation revokes every binding of a leaver at once; see [Directory sync with SCIM](https://neuralinverse.com/docs/govern/scim/).
- Review decisions are written to the audit log; see [Audit log](https://neuralinverse.com/docs/govern/audit/).
