> For the complete documentation index, see [llms.txt](https://documentation.immuta.com/saas/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://documentation.immuta.com/saas/request/review-access-requests/reference-guides/review-flows.md).

# Review Flows

Review flows define the approval process for access requests. When a user requests access to a data product, asset, or column (masking exception), the review flow dictates everything from the request form the user will complete, to if they get automatically approved, to the specific data stewards that must review the request.

## Dynamic review flows

{% hint style="info" %}

#### New feature

Immuta is gradually rolling out dynamic review flows to accounts. If you don't see this feature in the Request app, you can contact your Immuta support professional to ask about availability for your account.
{% endhint %}

Dynamic review flows are specific to each asset or data product they are attached to. Review flows are dynamic; depending on each user's attributes or request form answers, the result of the review flow may be automated determinations or lead to a specific reviewer. Dynamic review flows allow you to put your manual decision trees into Immuta and allow you to provide the right people access to data at the right time (when they actually need it).

When a user requests access to an asset or data product, they complete a request form, if one is configured. Immuta then evaluates the request based on the requestor’s attributes, the data consumer who will receive access, and the answers to the request form questions. The dynamic review flow uses these facts to determine whether the request can be approved automatically, denied automatically, sent to review assist, or routed to a human reviewer based on how the review flow is configured.

### Flow sections

A dynamic review flow contains four sections:

* **Request initialized**: The starting point for the flow. Every flow has one request initialized node.
* [**Request form**](#request-form): The form the data consumer completes when requesting access. The request form appears directly after request initialized. You can bind one request form to a flow, or leave the flow without a form if it does not need to collect answers.
* [**Decision**](#decision): A branching point in the flow. Each decision evaluates an expression and sends the request down a **Yes** or **No** branch. A flow can contain multiple decision nodes.
* [**Outcome**](#outcome): The result at the end of a branch. Every branch must end in an outcome.

#### **Request form**

A flow can use one request form. You can reuse the same request form across multiple flows.

When a form is configured, the data consumer completes it before the flow is evaluated. Answers can then be referenced in decision expressions.

For more information, see the [Request form reference guide](/saas/request/review-access-requests/reference-guides/request-forms.md).

#### **Decision**

A decision evaluates an expression and routes the request to a **Yes** or **No** branch.

Decisions are written with decision expressions that can use facts about:

* The request, such as whether it is self-service or the requested duration of access.
* The requestor, attributes about the user submitting the request.
* The consumer, attributes about the user who will gain access, if approved.
* Answers from the request form.

Decisions are based on **current** entitlements. If a user is granted access based on specific entitlements and then that entitlement is removed, the user's access will not be revoked. If this is a requirement, [use the Immuta Govern app to handle dynamic access based on user entitlements with subscription policies](/saas/govern/authoring-policies-in-secure/section-contents/reference-guides/subscription-policies.md).

#### Supported decision expression logic

The supported expression logic can be found in the dynamic review flow builder.

<table data-header-hidden="false" data-header-sticky data-first-column-sticky><thead><tr><th>Expression</th><th>Description</th><th>Options</th><th>Example</th></tr></thead><tbody><tr><td><code>@request.isSelfRequest</code></td><td>Evaluate based on if the access request is for the user submitting the request.</td><td><ul><li><code>true</code></li><li><code>false</code></li></ul></td><td><code>@request.isSelfRequest == true</code><br><br>If the access request is for themselves, direct them to the <strong>Yes</strong> outcome.</td></tr><tr><td><code>@request.form["id"]</code></td><td>Evaluate based on an answer from the request form.<br><br><em>Short answer questions are not supported.</em></td><td>-</td><td><code>@request.form["b19412c8-9599-4f4a-b2a9-ae456882f13b"] == "Fraud detection"</code><br><br>If the requestor answered the specific question in the request form with <code>Fraud detection</code>, direct them to <strong>Yes</strong> outcome.</td></tr><tr><td><code>@request.duration</code></td><td>Evaluate based on the duration of access being requested.</td><td><ul><li><code>hours (h)</code></li><li><code>days (d)</code></li><li><code>months (mo)</code></li><li><code>years (y)</code></li></ul></td><td><code>@request.duration &#x3C; 4h</code><br><br>If the requestor requested access to the data for less than four hours, direct them to the <strong>Yes</strong> outcome.</td></tr><tr><td><code>@consumer.groups</code></td><td>Evaluate based on the <a data-footnote-ref href="#user-content-fn-1">data consumer's</a> groups.</td><td><ul><li><code>contains</code></li><li><code>containsAny</code></li><li><code>containsAll</code></li></ul></td><td><code>@consumer.groups containsAll "Managers"</code><br><br>If the <a data-footnote-ref href="#user-content-fn-1">data consumer</a> is in the group <code>Managers</code>, direct them to the <strong>Yes</strong> outcome.</td></tr><tr><td><code>@consumer.attributes[attribute_key]</code></td><td>Evaluate based on the <a data-footnote-ref href="#user-content-fn-1">data consumer's</a> attributes.</td><td><ul><li><code>contains</code></li><li><code>containsAny</code></li><li><code>containsAll</code></li></ul></td><td><p><code>@consumer.attributes["clearance"] containsAll "alpha"</code></p><p></p><p>If the <a data-footnote-ref href="#user-content-fn-1">data consumer</a> has the attribute <code>clearance.alpha</code>, direct them to the <strong>Yes</strong> outcome.</p></td></tr><tr><td><code>@consumer.permissions</code></td><td>Evaluate based on the <a data-footnote-ref href="#user-content-fn-1">data consumer's</a> Immuta permissions.</td><td><ul><li><code>contains</code></li><li><code>containsAny</code></li><li><code>containsAll</code></li></ul></td><td><p><code>@consumer.permissions containsAny ["GOVERNANCE", "USER_ADMIN" ]</code></p><p></p><p>If the <a data-footnote-ref href="#user-content-fn-1">data consumer</a> has either the <code>GOVERNANCE</code> or <code>USER_ADMIN</code> Immuta permission, direct them to the <strong>Yes</strong> outcome.</p></td></tr><tr><td><code>@requestor.groups</code></td><td>Evaluate based on the <a data-footnote-ref href="#user-content-fn-2">requestor's</a> groups.</td><td><ul><li><code>contains</code></li><li><code>containsAny</code></li><li><code>containsAll</code></li></ul></td><td><code>@requestor.groups containsAll "Managers"</code><br><br>If the <a data-footnote-ref href="#user-content-fn-3">requestor</a> is in the group <code>Managers</code>, direct them to the <strong>Yes</strong> outcome.</td></tr><tr><td><code>@requestor.attributes</code></td><td>Evaluate based on the <a data-footnote-ref href="#user-content-fn-2">requestor's</a> attributes.</td><td><ul><li><code>contains</code></li><li><code>containsAny</code></li><li><code>containsAll</code></li></ul></td><td><p><code>@requestor.attributes["clearance"] containsAll "alpha"</code></p><p></p><p>If the <a data-footnote-ref href="#user-content-fn-3">requestor</a> has the attribute <code>clearance.alpha</code>, direct them to the <strong>Yes</strong> outcome.</p></td></tr><tr><td><code>@requestor.permissions</code> </td><td>Evaluate based on the <a data-footnote-ref href="#user-content-fn-2">requestor's</a> permissions.</td><td><ul><li><code>contains</code></li><li><code>containsAny</code></li><li><code>containsAll</code></li></ul></td><td><p><code>@requestor.permissions containsAny ["GOVERNANCE", "USER_ADMIN" ]</code></p><p></p><p>If the <a data-footnote-ref href="#user-content-fn-3">requestor</a> has either the <code>GOVERNANCE</code> or <code>USER_ADMIN</code> Immuta permission, direct them to the <strong>Yes</strong> outcome.</p></td></tr></tbody></table>

You can also combine expressions with `OR` and `AND`. For example:

```
@request.isSelfRequest == true AND
@consumer.groups contains "finance-analysts"
```

#### **Outcome**

An outcome defines what happens when a request reaches the end of a branch. Every branch in a dynamic review flow must end in one of these outcomes.

* **Automatically approve**: In cases where data is low-risk or public, you can choose for access requests to be automatically approved. This removes the need for manual intervention by a steward. Additional information must be provided when opting for access requests to have automatic approval:
  * **Justification**: You are required to provide a reason why this data should be automatically accessible.
  * **Duration**: A set duration can be provided so that users are granted temporary access to the data but must request access again once their limit is reached. You can set these approvals to **Never expire** (permanent access) or expire **After a set duration** (temporary access).
* **Automatically deny**: Denies the request without sending it to a reviewer. The data consumer is not granted access. Additional information must be provided when opting for access requests to have automatic denial:
  * **Justification**: You are required to provide a reason why this data should be automatically denied.
* **Human review**: Routes the request to the reviewers configured for the outcome. Reviewers make the final approval or denial determination.
  * When setting human review, you must also configure:
    * One or more reviewers or reviewer sources.
    * Whether **Any** or **All** reviewers must approve. When **Any** is selected, one reviewer from the configured sources can make the determination. When **All** is selected, each configured reviewer source must provide a determination before the request is complete.
    * Whether approved access must be temporary.
      * An optional maximum duration for temporary access.
* **Review Assist**: Evaluates the request automatically using available request and identity context, as well as previous access request determinations. Depending on its assessment, review assist can approve the request, approve it temporarily, or deny it instantly without any human intervention. For more information about review assist, see the [Understanding review assist guide](/saas/request/review-access-requests/reference-guides/understanding-review-assist.md).
  * When setting review assist, you must also configure the human-review fallback settings that review assist uses when it cannot make a confident determination:

    * One or more reviewers or reviewer sources.
    * Whether **Any** or **All** reviewers must approve.
    * Whether approved access must be temporary.
      * An optional maximum duration for temporary access.

    Review assist is available for data access requests, but not masking exception requests.

### Use cases

<details>

<summary>Automatically approve short-term access for approved data consumers</summary>

A finance analytics team regularly requests access to a reporting data product for short-term analysis. Analysts should not need to wait for a steward when they request access for themselves, belong to the approved analyst group, and need access for 30 days or less.

This can easily be configured using the dynamic review flow:

1. **Confirm that the request is self-service** by evaluating `@request.isSelfRequest == true`.
2. **Confirm that the consumer is an approved analyst** by evaluating `@consumer.groups contains "finance-analysts"`.
3. **Confirm that the requested duration is within the limit** by evaluating `@request.duration <= 30 days`.
4. **Automatically approve** requests that meet all three conditions.
5. **Route other requests to human review** for additional consideration.

<figure><img src="https://1751699907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlWBda5Pt4s8apEhzXGl7%2Fuploads%2FBQxrdjstudeSqFTpG9Zn%2FScreenshot%202026-10-07%20at%203.32.05%E2%80%AFPM.png?alt=media&amp;token=a47d1207-97be-40d4-b414-ec88997dfeff" alt=""><figcaption></figcaption></figure>

This gives analysts a fast path for routine work while preserving review for exceptions.

</details>

<details>

<summary>Automatically deny ineligible users and use review assist for other requests</summary>

An organization publishes a customer data product that interns are not allowed to access. Requests from other users can be evaluated using historical approval patterns, with human review available when review assist cannot make a determination.

This can easily be configured using the dynamic review flow:

1. **Check whether the consumer is an intern** by evaluating `@consumer.groups contains "Interns"`.
2. **Automatically deny** requests from consumers in the `Interns` group.
3. **Send all other requests to a review assist outcome** configured with human-review fallback settings.
4. **Automatically approve, temporarily approve, or automatically deny** requests based on review assist's recommendation.
5. **When review assist cannot make a determination**, route requests to the configured human reviewers.

<figure><img src="https://1751699907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlWBda5Pt4s8apEhzXGl7%2Fuploads%2Fy8lOar57IboZPCPMBIZ3%2FScreenshot%202026-10-08%20at%203.15.41%E2%80%AFPM.png?alt=media&amp;token=db53b2a9-8c95-4a09-bb41-23d76b28160d" alt=""><figcaption></figcaption></figure>

</details>

<details>

<summary>Automatically approve agent access for a fraud investigation</summary>

A fraud analyst uses Claude to investigate suspicious transactions. Claude accesses data through [agentic data access](/saas/agentic-data-access/agentic-data-access-reference-guide.md), acting on behalf of the analyst. When the analyst doesn’t have access to the required data, Claude’s query is blocked.

The analyst submits an access request through Immuta and selects **Fraud investigation** as the intended use in the request form. The dynamic review flow evaluates that answer along with the analyst’s group membership.

This can easily be configured using the dynamic review flow:

1. **Confirm the intended use** by evaluating `@request.form["intended-use"] == "fraud-investigation"`.
2. **Confirm that the consumer is an approved fraud analyst** by evaluating `@consumer.groups contains "fraud-analysts"`.
3. **Automatically approve temporary access** when both conditions are true.
4. **Route other requests to human review** instead of granting access automatically.

<figure><img src="https://1751699907-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FlWBda5Pt4s8apEhzXGl7%2Fuploads%2FjhizlUcfghEgsGIwIUVI%2FScreenshot%202026-10-08%20at%203.07.28%E2%80%AFPM.png?alt=media&amp;token=63ae1683-872b-41a7-9bd2-ca97012f6348" alt=""><figcaption></figcaption></figure>

This lets the analyst continue using Claude without waiting for a manual approval when the request matches a pre-approved fraud investigation workflow. The agent receives governed, temporary access on behalf of the analyst, rather than using the analyst’s credentials as a standing privilege.

</details>

### Inheritance in assets

Review flows are inherited through the hierarchy in assets. However, any asset level can be overridden to have a unique review flow. If a parent asset has an overridden review flow, the new review flow will trickle down to its children.

## Legacy review flows

Legacy review flows live within request forms. They can be reused just like request forms and they are static. The review flow is the same for every user that fills out the request form.

### Configuration modes

When setting up a review flow within a request form, you must dictate how the reviewers (data stewards) are managed. There are two primary modes:

1. **In the request form (centralized)**: The review flow is defined directly within the request form. Every asset, data product, or column that uses this form will follow the same set of reviewers. This is ideal for standardized processes across the organization.
2. **Delegate (decentralized)**: The review flow is managed and set at the individual asset or data product. This allows local owners to configure their own specific reviewers. **This is ideal to provide flexibility for different departments or data types while still using the same underlying request questions.**

{% hint style="warning" %}
When using the delegate mode, stewards configured at the data product or asset level will not have permission to edit the request form's questions.
{% endhint %}

### Inheritance in assets

Review flows are inherited through the hierarchy in assets. However, the request form's defined review flow always takes precedence. This means that if data stewards are assigned in the request forms, the review flows assigned or inherited through the asset hierarchy are **Inactive**.

If you want to define review flows at the asset level, you must configure the review flow as **Delegate** in the request form.

#### Automatic approval

In cases where data is low-risk or public, you can choose for access requests to be automatically approved. This removes the need for manual intervention by a steward. Additional information must be provided when opting for access requests to have automatic approval:

* **Justification**: You are required to provide a reason why this data should be automatically accessible.
* **Duration**: A set duration can be provided so that users are granted temporary access to the data but must request access again once their limit is reached. You can set these approvals to **Never expire** (permanent access) or expire **After a set duration** (temporary access).

## Assigning data stewards

If human review is required, the data stewards are assigned within the review flow. If an access request requires all data stewards' determinations, then for every group, attribute, or permission listed in the review flow, a data steward from that [source](#steward-sources) must make a determination. If a data steward qualifies for multiple sources, their determination will count for each of the sources they have.

See the [Understanding approval logic section](#understanding-approval-logic) to understand how assigning data stewards impacts determinations on access requests.

### Steward sources

You can select reviewers from several categories:

* **User**: A specific individual.
* **Group**: Any member of a specific user group.
* **Attribute**: Users associated with a specific metadata attribute.
* **Global permission**: Users with a global Immuta permission (e.g., `GOVERNANCE`).
* **Domain permission**: Users with a domain-specific permission (e.g., `Manage Data Products`) on the specific domain where the data product resides.
* **Catalog permission**: The specific owner assigned to the asset in the external catalog. See the [section below for details](#dynamic-steward-lookups).

#### Dynamic steward lookups

The catalog permission source for data stewards is dynamic. The system looks up the specific owner assigned to the asset in the external catalog.

Currently only [asset owners](https://docs.atlan.com/product/capabilities/discovery/how-tos/add-owners) from Atlan are supported. The catalog **must** be [configured in the Govern app](/saas/configuration/tags/catalogs/configure.md) for the asset owner information to populate.

### Understanding approval logic

Approvals in the Request app are marked based on the source of the data steward, not individuals. If your flow requires all stewards to approve, this means one representative from each assigned source must approve. See the examples below:

{% tabs %}
{% tab title="Single approver" %}
If an access request requires **any data steward's** determination, then once a single data steward makes a determination, it goes into effect.

* If approved:
  * [Access to the data objects will be auto-provisioned](#user-content-fn-4)[^4] in the data platform(s) for the requested data. This is done natively in the data platform, which means the requesting user can query those data objects directly from the data platform. This provisioning is represented as an [understandable and scalable Immuta policy](/saas/request/configure/reference-guides/understanding-access-provisioning-and-underlying-policies-in-immuta.md) that will be combined with any existing policies.
  * For masking exceptions, approved columns will be auto-provisioned with unmasked access in the data platform(s) where the user has access to the data source. This exception to the masking policy is represented as an [understandable and scalable Immuta policy](/saas/request/configure/reference-guides/understanding-masking-exceptions-and-underlying-policies.md) that will be combined with any existing policies.
* If denied, the user will not be granted access to the data.
  {% endtab %}

{% tab title="Multiple approvers" %}
If an access request requires **all data stewards'** determinations, then for every group, attribute, or permission listed in the request form, a data steward from that source must make a determination. If a data steward qualifies for multiple sources, their determination will count for each of the sources they have.

For example, if the request form lists users with the `GOVERNANCE` permission and users with the HR group as data stewards, then one user with the `GOVERNANCE` permission and one user with the HR group must approve to satisfy each of those conditions. A single user may approve for all conditions in a request form if they have the necessary permissions.

Once a determination is made by every source listed in the request form, it goes into effect.

* If approved:
  * [Access to the data objects will be auto-provisioned](#user-content-fn-4)[^4] in the data platform(s) for the data requested. This is done natively in the data platform, which means the requesting user can query those data objects directly from the data platform. This provisioning is represented as an [understandable and scalable Immuta policy](/saas/request/configure/reference-guides/understanding-access-provisioning-and-underlying-policies-in-immuta.md) that will be combined with any existing policies.
  * For masking exceptions, approved columns will be auto-provisioned with unmasked access in the data platform(s) where the user has access to the data source. This exception to the masking policy is represented as an [understandable and scalable Immuta policy](/saas/request/configure/reference-guides/understanding-masking-exceptions-and-underlying-policies.md) that will be combined with any existing policies.
* If denied by even a single data steward, the entire access request is denied and the user will not be granted access to the data.
* If there is a mix of approvals and temporary approvals, the user will be approved access to the data for the shortest time period that any of the data stewards picked.
  {% endtab %}
  {% endtabs %}

[^1]: The user who will gain access if the request is approved.

[^2]: The user submitting the access request.

[^3]: The user making the access request.

[^4]: When supported by the [data platform](/saas/configuration/integrations.md#integrations-overview)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://documentation.immuta.com/saas/request/review-access-requests/reference-guides/review-flows.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
