> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ravenna.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Access policies

> Define who can request access, approval requirements, and how long access lasts with access policies.

## Data model

`AccessPolicy` fields:

| Field | Type | Description |
| - | - | - |
| `name` | string | Display name |
| `description` | string | When this policy should be used |
| `icon` | string | Lucide icon name |
| `color` | string | Hex color for visual identification |
| `isDefault` | boolean | Marks the organization's default policy |
| `requiresBusinessJustification` | boolean | Whether requesters must provide a reason |
| `durationMode` | `choice` \| `fixed` \| `none` | Who controls the grant length. `choice` means the requester picks from `durationOptions`, `fixed` means `defaultDuration` is enforced, `none` means permanent access. |
| `durationOptions` | string\[] | Durations offered when `durationMode` is `choice`, in short-form notation such as `12h`, `1w`, `30d`. At least one is required in that mode. `forever` means no expiry. |
| `defaultDuration` | string \| null | Required when `durationMode` is `fixed`. Also used to preselect an option in `choice` mode when it appears in `durationOptions`. |
| `ownerId` | string | User responsible for managing the policy |
| `approverMode` | `template` \| `explicit` | Selects the approval routing style. `template` uses `approvalTemplateId`; `explicit` uses the inline `approvers` / `approverGroups` / `roleBasedApprovers` and `approverPolicy` on the policy. |
| `approvalTemplateId` | string \| null | Used when `approverMode` is `template`. When null in template mode, requests auto-approve. |
| `approverPolicy` | `ANY` \| `MAJORITY` \| `ALL` \| null | Round policy for the inline round when `approverMode` is `explicit`. `THRESHOLD` is not supported in explicit mode. |
| `roleBasedApprovers` | string\[] | Dynamic role identifiers (for example, manager, application owner) used in explicit mode. Resolved at apply time. |

Relationships:

* `eligibleGroups` (`UserGroup[]`): groups allowed to request
* `ineligibleGroups` (`UserGroup[]`): groups explicitly excluded
* `approvers` (`User[]`): explicit-mode user approvers
* `approverGroups` (`UserGroup[]`): explicit-mode group approvers, expanded at apply time
* `accessLevels` (`AccessLevel[]`): levels this policy governs

Policy types:

* **Shared** policies are created in **Settings** > **Applications** > **Policies** and can be linked to many access levels.
* **Custom** policies are created inline on a single access level by sending `customAccessPolicy` instead of `accessPolicyId` when creating or updating the level. They are named after the level and are excluded from policy lists, the access policy picker, and the copilot `list_access_policies` tool.
* **External** policies are created by an integration sync for a single [external access level](/documentation/automate/access-provisioning/applications#external-access-levels). Like custom policies, they are excluded from policy lists and the picker, and they can't be linked to another level, archived, or deleted on their own.

***

## Policy evaluation flow

1. User submits an access request for an access level.
2. System looks up the access level's linked access policy.
3. Eligibility is checked: user must be in `eligibleGroups` (or no groups set) and must not be in `ineligibleGroups`. Deny wins over allow, so membership in an ineligible group excludes the user even when they are also in an eligible group.
4. If eligible, approval routing is applied based on `approverMode`:
   * `template`: the referenced `approvalTemplateId` is applied. If null, the request auto-approves.
   * `explicit`: a single inline round is created using `approvers`, `approverGroups`, and `roleBasedApprovers`, with `approverPolicy` as the round policy. Groups expand and dynamic roles resolve at apply time. If no approvers resolve, the request auto-approves.
5. If ineligible: the request is blocked.

***

## Policy-driven form fields

The `DURATION` and `BUSINESS_JUSTIFICATION` fields on an access request form are gated by the selected access level's policy:

* The Duration field renders only for access levels whose policy uses `durationMode: choice` and has at least one entry in `durationOptions`. It is hidden for `fixed` and `none`.
* The Business Justification field renders only for access levels whose policy has `requiresBusinessJustification` set.
* When either field renders, it is required. Visibility implies requiredness, so the form's own required flag does not need to be set.

Both gates are honored in the web form and in Slack modals.

***

## Constraints

* Policies are organization-scoped.
* A shared policy can be linked to multiple access levels across different applications.
* A custom policy belongs to exactly one access level. Assigning it to another level by `accessPolicyId` is rejected with `CUSTOM_POLICY_NOT_ASSIGNABLE`. An access level update can send `accessPolicyId` or `customAccessPolicy`, not both.
* A custom policy cannot be archived, deleted, or reassigned to other levels through the access policy endpoints. Those requests fail with `CUSTOM_POLICY_MANAGED_BY_ACCESS_LEVEL`. Ravenna deletes it when its access level is deleted, when the level switches to a shared policy, or when its application is deleted.
* `durationMode: fixed` requires a valid finite `defaultDuration`. Use `none` for permanent access rather than an unbounded fixed duration.
* A requested duration that is not one of the policy's `durationOptions` snaps to the closest allowed option rather than being accepted as-is. This matters for API and MCP submissions, where the duration is free-form. If no option can be resolved, the request is rejected.
* Duration values are stored in short-form notation: `m` for minutes, `h` for hours, `d` for days, `w` for weeks. There is no month unit. The admin UI stores a month as `30d` and displays `30d` as **1 Month**.
* Switching duration modes preserves the inactive mode's configuration, so a stored `defaultDuration` may not be present in `durationOptions`.
* Removing a policy from an access level means that level falls back to auto-approval.
* The `isDefault` flag marks the organization's default policy, used when no specific policy is assigned to an access level.
* Explicit mode supports `ANY`, `MAJORITY`, and `ALL` for `approverPolicy`. `THRESHOLD` is rejected because the inline form does not collect the required approver count; use an approval template for threshold routing.
* In explicit mode, the form validator requires at least one entry in `approvers` (users, groups, and roles are all selected through the same field). At request time, groups expand and roles resolve; if the final approver set is empty, the request auto-approves rather than blocking.


## Related topics

- [Access provisioning](/documentation/automate/access-provisioning/overview.md)
- [Available tools](/documentation/automate/mcp/tools.md)
- [Create an access policy](/api/access-policy/create-an-access-policy.md)
- [Delete an access policy](/api/access-policy/delete-an-access-policy.md)
- [Get an access policy](/api/access-policy/get-an-access-policy.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.