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

# Attribute-based access control

This reference explains LangSmith's Attribute-Based Access Control (ABAC) system, which enables fine-grained access control based on resource attributes, complementing [RBAC](/langsmith/rbac). For automated user provisioning into roles, see [SCIM](/langsmith/user-management#set-up-scim-for-your-organization).

<Note>
  ABAC (Attribute-Based Access Control) is an Enterprise feature for managing fine-grained access control. If you are interested in this feature, [contact our sales team](https://www.langchain.com/contact-sales). Other plans default to using the Admin role for all users.
</Note>

ABAC complements [Role-Based Access Control (RBAC)](/langsmith/rbac) by adding tag-based conditions to access decisions. While RBAC grants blanket permissions based on a user's role (e.g., "can read all projects"), ABAC lets you restrict or grant access based on resource tags (e.g., "can only read projects tagged with Environment=Development").

<Note>
  Roles and resource tags can be managed via the UI or API. ABAC policies are configurable via the [API](https://api.smith.langchain.com/docs#/access_policies). Once configured, policies are automatically enforced in both the API and the UI.
</Note>

## Before you begin

* [Set up resource tags](/langsmith/set-up-resource-tags) in your workspace.
* ABAC currently only supports `resource_tag_key` as an `attribute_name` in policies, for evaluating against resource tags. No other attributes are supported yet.

## Enable ABAC for self-hosted deployments

1. ABAC requires a [self-hosted](/langsmith/self-hosted) LangSmith deployment running Helm chart 0.11.28 or later (application version 0.12.1). Once you've upgraded, use one of the following options to enable ABAC:

   * **Enable for a specific organization:** Run the following against your LangSmith PostgreSQL database, replacing `<organization_id>` with the ID copied from the organization settings page in the UI:

     ```sql theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
     UPDATE organizations SET config = config || '{"can_use_abac": true}' WHERE id = '<organization_id>' AND NOT is_personal;
     ```

   * **Enable for all organizations:** Add the following environment variable to `commonEnv` in your `values.yaml`:

     ```yaml theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
     DEFAULT_ORG_FEATURE_CAN_USE_ABAC: "true"
     ```

     <Note>
       This environment variable has no effect on personal organizations, because [RBAC](/langsmith/rbac) is not enabled for personal organizations.
     </Note>

2. Set up authentication. To manage access policies via the API, you need a Personal Access Token (PAT) from an [Organization Admin](/langsmith/rbac#organization-admin) user, or an organization-scoped service key with Organization Admin permissions. Set the following environment variables before running any scripts:

   ```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
   export LANGSMITH_API_KEY="your_admin_api_key"
   # Required for self-hosted or EU deployments:
   # export LANGCHAIN_ENDPOINT="https://eu.api.smith.langchain.com"
   # export LANGCHAIN_ENDPOINT="https://langsmith.yourdomain.com/api"
   ```

## Access policy structure

An access policy defines conditions under which access is granted or denied. Here's the structure:

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "name": "Policy Name",
  "description": "Optional description",
  "effect": "allow | deny",
  "condition_groups": [
    {
      "permission": "projects:read",
      "resource_type": "project",
      "conditions": [
        {
          "attribute_name": "resource_tag_key",
          "attribute_key": "Environment",
          "operator": "equals",
          "attribute_value": "Production"
        }
      ]
    }
  ],
  "role_ids": ["<role-uuid>"]
}
```

### Effect

The `effect` determines what happens when conditions match:

* **`allow`** - Grant access when conditions match
* **`deny`** - Block access when conditions match

<Note>
  Deny policies always take precedence. If both an allow and deny policy match, access is denied.
</Note>

### Condition groups

The `condition_groups` array contains one or more condition groups. Multiple condition groups are evaluated with **OR logic** - if any group matches, the policy applies.

Each condition group specifies:

* **`permission`** - The permission this group applies to
* **`resource_type`** - The resource type to match
* **`conditions`** - Array of conditions (evaluated with **AND logic** within the group)

#### Resource types and permissions

| Resource type       | Supported permissions                                                                                                                                                             |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `project`           | `projects:read`, `projects:update`, `projects:delete`, `runs:read`, `runs:share`, `runs:delete`, `projects:increase-trace-tier`, `projects:decrease-trace-tier`                   |
| `prompt`            | `prompts:read`, `prompts:update`, `prompts:delete`, `prompts:share`, `prompts:tag`                                                                                                |
| `dataset`           | `datasets:read`, `datasets:update`, `datasets:delete`, `datasets:share`                                                                                                           |
| `deployment`        | `deployments:read`, `deployments:update`, `deployments:delete`                                                                                                                    |
| `mcp_server`        | `mcp-servers:read`, `mcp-servers:invoke`, `mcp-servers:update`, `mcp-servers:delete`. See [Fleet tool access control](/langsmith/fleet/access-and-oversight#tool-access-control). |
| `fleet_integration` | `mcp-servers:read`, `mcp-servers:invoke`. See [Fleet tool access control](/langsmith/fleet/access-and-oversight#tool-access-control).                                             |

<Note>
  Runs don't have their own tags. Run permissions (`runs:read`, `runs:create`, `runs:share`, `runs:delete`) are evaluated against the parent project's tags.
</Note>

#### Conditions

Each condition in the `conditions` array specifies:

* **`attribute_name`** - Currently only `resource_tag_key` is supported
* **`attribute_key`** - The tag key to match (e.g., `Environment`, `Team`)
* **`operator`** - The comparison operator
* **`attribute_value`** - The value to compare against

##### Operators

| Operator                 | Description                                      |
| ------------------------ | ------------------------------------------------ |
| `equals`                 | Exact match (case sensitive)                     |
| `not_equals`             | Values differ (case sensitive)                   |
| `equals_ignore_case`     | Exact match (case insensitive)                   |
| `not_equals_ignore_case` | Values differ (case insensitive)                 |
| `matches`                | Glob pattern matching with `*` and `?` wildcards |
| `not_matches`            | Match when value doesn't match glob pattern      |

##### `_if_exists` variants

Each operator has an `_if_exists` variant that matches by default when the tag key is absent, or evaluates the condition normally when the tag exists:

| Operator                           | Description                                                       |
| ---------------------------------- | ----------------------------------------------------------------- |
| `equals_if_exists`                 | Exact match (case sensitive), or if tag key absent                |
| `not_equals_if_exists`             | Values differ (case sensitive), or if tag key absent              |
| `equals_ignore_case_if_exists`     | Exact match (case insensitive), or if tag key absent              |
| `not_equals_ignore_case_if_exists` | Values differ (case insensitive), or if tag key absent            |
| `matches_if_exists`                | Glob pattern match, or if tag key absent                          |
| `not_matches_if_exists`            | Match when value doesn't match glob pattern, or if tag key absent |

<Tip>
  In an **allow** policy, `_if_exists` variants grant access to resources that either match the condition or don't have the specified tag key. In a **deny** policy, they block resources that either match the condition or don't have the tag key.
</Tip>

### Roles

The `role_ids` array specifies which workspace roles the policy applies to. When a user with that role accesses a resource, the policy conditions are evaluated.

Policies can be attached to roles when creating the policy, or attached later via the API.

## Managing access policies

Access policies are managed via the LangSmith API by [Organization Admins](/langsmith/rbac#organization-admin). Before creating policies, [set up resource tags](/langsmith/set-up-resource-tags) in your workspace.

## How ABAC works with RBAC

[RBAC](/langsmith/rbac) permissions and ABAC policies are both considered when determining access to resources:

* ABAC **deny** policies override RBAC permissions
* ABAC **allow** policies can grant access even without RBAC permissions
* If no ABAC policies match, the system falls back to RBAC

### Policy evaluation outcomes

**Feature combinations:**

| RBAC enabled | ABAC enabled | Behavior                                            |
| ------------ | ------------ | --------------------------------------------------- |
| ✗            | ✗            | All workspace members have Admin-level access       |
| ✓            | ✗            | Standard RBAC - access based on role permissions    |
| ✓            | ✓            | RBAC + ABAC - fine-grained tag-based access control |

**When both RBAC and ABAC are enabled:**

| RBAC permits | Allow policy matches | Deny policy matches | Result                           |
| ------------ | -------------------- | ------------------- | -------------------------------- |
| ✓            | ✓                    | ✗                   | **Allowed**                      |
| ✓            | ✗                    | ✗                   | **Allowed** (RBAC fallback)      |
| ✓            | ✓                    | ✓                   | **Denied** (deny wins)           |
| ✓            | ✗                    | ✓                   | **Denied** (deny wins)           |
| ✗            | ✓                    | ✗                   | **Allowed** (ABAC grants access) |
| ✗            | ✗                    | ✗                   | **Denied**                       |
| ✗            | ✓                    | ✓                   | **Denied** (deny wins)           |

## Example scenarios

### 1. Annotator team assignment

Allow annotators to only access datasets tagged for their team:

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "name": "Annotator Team A Access",
  "effect": "allow",
  "condition_groups": [{
    "permission": "datasets:read",
    "resource_type": "dataset",
    "conditions": [{
      "attribute_name": "resource_tag_key",
      "attribute_key": "Annotation-Team",
      "operator": "equals",
      "attribute_value": "Team-A"
    }]
  }]
}
```

### 2. Block sensitive data

Deny access to datasets containing PII. Since deny policies override allow policies, this blocks access even for users with RBAC permissions:

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "name": "Block PII Datasets",
  "effect": "deny",
  "condition_groups": [{
    "permission": "datasets:read",
    "resource_type": "dataset",
    "conditions": [{
      "attribute_name": "resource_tag_key",
      "attribute_key": "Contains-PII",
      "operator": "equals",
      "attribute_value": "true"
    }]
  }]
}
```

### 3. Application-based access with wildcards

Allow engineers to access projects for any application in the "chatbot" family using glob patterns:

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "name": "Chatbot Apps Access",
  "effect": "allow",
  "condition_groups": [{
    "permission": "projects:read",
    "resource_type": "project",
    "conditions": [{
      "attribute_name": "resource_tag_key",
      "attribute_key": "Application",
      "operator": "matches",
      "attribute_value": "chatbot-*"
    }]
  }]
}
```

### 4. Client and purpose isolation (AND logic)

Grant access only if both conditions are met - dataset is for training AND belongs to a specific client:

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "name": "Client Training Data Access",
  "effect": "allow",
  "condition_groups": [{
    "permission": "datasets:read",
    "resource_type": "dataset",
    "conditions": [
      {
        "attribute_name": "resource_tag_key",
        "attribute_key": "Purpose",
        "operator": "equals",
        "attribute_value": "Training"
      },
      {
        "attribute_name": "resource_tag_key",
        "attribute_key": "Client",
        "operator": "equals",
        "attribute_value": "Acme-Corp"
      }
    ]
  }]
}
```

### 5. Client data plus resources without a `Client` tag using `_if_exists`

Consultants don't have RBAC `datasets:read` permission, but this policy grants them access to datasets tagged `Client=Acme-Corp`, as well as datasets that don't have a `Client` tag at all. Datasets tagged with a different client (e.g., `Client=Other-Corp`) remain blocked:

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "name": "Acme Consultant Access",
  "effect": "allow",
  "condition_groups": [{
    "permission": "datasets:read",
    "resource_type": "dataset",
    "conditions": [{
      "attribute_name": "resource_tag_key",
      "attribute_key": "Client",
      "operator": "equals_if_exists",
      "attribute_value": "Acme-Corp"
    }]
  }]
}
```

## Troubleshooting

**Access unexpectedly denied?**

* Check if a deny policy is matching (deny always takes precedence)
* Check if the user has RBAC permissions or a matching allow policy
* Verify the resource has the expected tag and value
* Deny policies with `_if_exists` operators block resources missing that tag key
* For case-sensitive operators (`equals`, `not_equals`), check for case mismatches
* With multiple conditions in a group, all must match (AND logic)

**Access unexpectedly granted?**

* Review RBAC permissions (users may have access via their role)
* Check if an allow policy is too broad (e.g., using wildcards)
* `_if_exists` operators match resources missing that tag key

**Policy not taking effect?**

* Confirm the policy is attached to the correct role
* Verify the user has that role in the workspace
* Check that `resource_type` and `permission` match the resource being accessed

***

<div className="source-links">
  <Callout icon="terminal-2">
    [Connect these docs](/use-these-docs) to Claude, VSCode, and more via MCP for real-time answers.
  </Callout>

  <Callout icon="edit">
    [Edit this page on GitHub](https://github.com/langchain-ai/docs/edit/main/src/langsmith/abac.mdx) or [file an issue](https://github.com/langchain-ai/docs/issues/new/choose).
  </Callout>
</div>
