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

# The Access Policy object

> How an Access Policy grants apps and entitlements to every identity that matches its condition, and when a policy takes effect.

An Access Policy grants apps, and optionally specific entitlements on them, to every identity that
matches its condition. Each app on a policy can also be pre-approved, so requests the policy
creates for the app and its listed entitlements skip approval.

```json The Access Policy object theme={null}
{
  "id": "2e3f4a5b-6c7d-4e8f-9a0b-1c2d3e4f5a6b",
  "name": "Engineering baseline",
  "business_justification": "Every engineer needs source control from day one.",
  "status": "published",
  "is_enabled": true,
  "apps": [
    {
      "id": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
      "label": "GitHub",
      "is_preapproved": true,
      "entitlements": [
        { "id": "4d5e6f70-8192-4a3b-8c4d-5e6f70819203", "label": "Member" }
      ]
    }
  ],
  "access_condition": {
    "attribute": { "label": "Department", "value": "identity.custom_attributes['Department']" },
    "equals": { "label": "Engineering", "value": "Engineering" }
  },
  "is_everyone_condition": false
}
```

## Attributes

| Field | Type | Description |
| - | - | - |
| `id` | string | Unique identifier for the policy. Always present. |
| `name` | string | The policy's name. Always present. |
| `business_justification` | string | Why the policy exists. Always present. |
| `status` | string | `draft` or `published`. See [Drafts, publishing, and enabling](#drafts-publishing-and-enabling). Always present. |
| `is_enabled` | boolean | Whether the policy is enabled. Always present. |
| `apps` | array | The apps the policy grants, each with its entitlements. See [Grants](#grants). Always present. |
| `access_condition` | object | The condition an identity must match. See [Conditions](https://docs.lumos.com/reference/v1/guides/conditions.md). Always present. |
| `is_everyone_condition` | boolean | Whether the policy applies to everyone. Always present. |
| `owners` | object | The users and groups that own the policy. Only present with an owners `expand`. See [Owners](#owners). |

Each item in `apps`:

| Field | Type | Description |
| - | - | - |
| `id` | string | The [app](https://docs.lumos.com/reference/v1/objects/app.md)'s ID. |
| `label` | string | The app's display name. Returned on reads only. |
| `is_preapproved` | boolean | Whether requests the policy creates for this app, and for each entitlement in `entitlements`, are pre-approved. |
| `entitlements` | array | The [entitlements](https://docs.lumos.com/reference/v1/objects/entitlement.md) granted on the app, each `{id, label}`. An entitlement's `label` is returned on reads only. |

A write body that includes `label` on an app or entitlement returns `400`.

## Grants

Each grant is an entitlement ID in `apps[].entitlements[].id`. It's the same ID that
[Get Entitlement](https://docs.lumos.com/api-reference/v1/entitlements/get-entitlement.md) takes. To grant access to the app
itself rather than to specific entitlements, omit `entitlements` or send an empty list.
[Migrate Access Policies](https://docs.lumos.com/reference/v1/migrate/access-policies.md) covers moving existing grants to
entitlement IDs.

A policy needs at least one app, and an empty `apps` list returns `400`. When you create or update
a policy, Lumos checks every ID in `apps`:

| Problem | Response |
| - | - |
| An app or entitlement ID that doesn't match one in your organization | `404` |
| An entitlement that can't be requested | `404` |
| An entitlement listed under an app it doesn't belong to | `400` with "One or more selected permissions are not available for the selected app." |

The `400` message calls grants "permissions".

## Drafts, publishing, and enabling

A policy grants access only while it's both published and enabled.

* **[Create](https://docs.lumos.com/api-reference/v1/access-policies/create-access-policy.md)** returns `201` with the new policy. It makes a draft unless you send
  `"status": "published"`, and it leaves the policy disabled unless you send `"is_enabled": true`.
  A draft can't be enabled, so on create, `"is_enabled": true` returns `400` unless you also send
  `"status": "published"`.
* **Publish** a draft by sending `"status": "published"` on
  [Update Access Policy](https://docs.lumos.com/api-reference/v1/access-policies/update-access-policy.md). You can't return a
  published policy to draft. Sending `"status": "draft"` for a published policy returns `400`.
* **Approval.** When your organization requires approval before publishing, creating a policy with
  `"status": "published"` returns `400`, and so does publishing a draft whose changes aren't
  approved. Create a draft and submit it for approval in the Lumos UI.
* **Update** a published policy with `PUT`, which replaces every field, or with `PATCH`, where a
  field you omit keeps its value and no field can be `null`. The update takes effect immediately. If
  the policy also has a draft version saved in Lumos, either call returns `400` with "Access policy
  already has a draft version."
* **Read** returns the published version when there is one, and the draft version otherwise.
* **Delete** removes the policy and the pre-approval it gave its apps, and returns `204`.

`status` takes only `draft` or `published`, so an uppercase value such as `PUBLISHED` returns `400`.

Updating or deleting a policy doesn't remove access that identities already received through it.
When an identity stops matching a policy, Lumos removes the access that the policy granted only if
your organization has enabled **Auto Run** in its Movers settings. Even then, Lumos keeps access
that the identity requested through the AppStore.

## Conditions

Send `access_condition` with the condition that identities must match, or send
`"is_everyone_condition": true` to apply the policy to everyone. Sending both returns `400` on every
write. The exception is the [everyone condition](https://docs.lumos.com/reference/v1/guides/conditions.md#everyone) that a
read returns: Lumos reads it as `"is_everyone_condition": true`, so you can send a read's
`access_condition` back as is.

Lumos checks the condition when you save it.
[What Lumos rejects](https://docs.lumos.com/reference/v1/guides/conditions.md#what-lumos-rejects) lists what returns `400`.

Reads set `is_everyone_condition` to `true` only for this exact condition, label included. Any other
condition that matches every identity reads back as `is_everyone_condition: false`.
[Conditions](https://docs.lumos.com/reference/v1/guides/conditions.md) documents the format, and the
[stored form](https://docs.lumos.com/reference/v1/guides/conditions.md#stored-form) that a read returns.

Two published policies can't have the same condition. If creating, publishing, or updating a policy
would give a published policy the same condition as another published policy, the call returns
`400` with "An access policy with these conditions already exists." Drafts can share a condition.

## Who can do what

The built-in roles can do the following:

| Role | Can |
| - | - |
| Admin | Every action: create, read, update, publish, enable, and delete. |
| Read Only Admin | Read every policy. |
| A policy's owners | Read the policy, and update the apps on it while it's a draft. |
| A policy's commenters | Read the policy. |

A custom role can also allow these actions. On a `PUT` or `PATCH`, Lumos checks permission for each
changed field on its own, so an owner can update a draft's `apps`, but gets `403` for a change to
its name, justification, or condition.

A call you aren't allowed to make returns `403`.

## Owners

[List Access Policies](https://docs.lumos.com/api-reference/v1/access-policies/list-access-policies.md) and
[Get Access Policy](https://docs.lumos.com/api-reference/v1/access-policies/get-access-policy.md) add each policy's `owners`
when you send one of these `expand` values:

| `expand` | What `owners` holds |
| - | - |
| `owners` | A `users` list and a `groups` list, with each owner as `{id}`. |
| `owners.users` | The same, except each user is a full [user](https://docs.lumos.com/reference/v1/objects/user.md). |
| `owners.groups` | The same, except each group is a full [group](https://docs.lumos.com/reference/v1/objects/group.md). |

With `expand=owners.users`, a policy's owners look like this:

```json theme={null}
"owners": {
  "users": [
    {
      "id": "1a2b3c4d-5e6f-7890-abcd-ef1234567890",
      "email": "ada@acme.com",
      "given_name": "Ada",
      "family_name": "Lovelace",
      "status": "active"
    }
  ],
  "groups": [{ "id": "2b3c4d5e-6f70-8901-bcde-f12345678901" }]
}
```

The group is `{id}` because only `owners.users` was sent. To get full users and full groups, send
both, such as `expand=owners.users,owners.groups`. Without an owners `expand`, the response has no
`owners`. A user that [List Users](https://docs.lumos.com/api-reference/v1/users/list-users.md) treats as
deleted isn't listed.

Any owners `expand` needs permission to call both List Users and
[List Groups](https://docs.lumos.com/api-reference/v1/groups/list-groups.md). Without both, the call returns `403`.

> [!NOTE]
>
> Lumos enables owners per organization. Until it's enabled for yours, an owners `expand` returns
> `400`. To enable it, contact your Lumos representative.

## Listing

[List Access Policies](https://docs.lumos.com/api-reference/v1/access-policies/list-access-policies.md) returns the
policies you can read, newest first. `name` limits the list to policies whose name contains that
text, ignoring case. A page can be empty while later pages still hold policies, as
[Short and empty pages](https://docs.lumos.com/reference/v1/pagination.md#short-and-empty-pages) describes.

## Endpoints

| Endpoint | Path |
| - | - |
| [List Access Policies](https://docs.lumos.com/api-reference/v1/access-policies/list-access-policies.md) | `GET /v1/access-policies` |
| [Create Access Policy](https://docs.lumos.com/api-reference/v1/access-policies/create-access-policy.md) | `POST /v1/access-policies` |
| [Get Access Policy](https://docs.lumos.com/api-reference/v1/access-policies/get-access-policy.md) | `GET /v1/access-policies/{access_policy_id}` |
| [Update Access Policy](https://docs.lumos.com/api-reference/v1/access-policies/update-access-policy.md) | `PUT /v1/access-policies/{access_policy_id}` |
| [Patch Access Policy](https://docs.lumos.com/api-reference/v1/access-policies/patch-access-policy.md) | `PATCH /v1/access-policies/{access_policy_id}` |
| [Delete Access Policy](https://docs.lumos.com/api-reference/v1/access-policies/delete-access-policy.md) | `DELETE /v1/access-policies/{access_policy_id}` |
