> ## 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.

# Building Conditions in Lumos

Lumos Conditions represent a recursive query language that allows you to define complex rules for filtering and matching identities in the Lumos platform.

**Current Usage:** Conditions are currently primarily used in Access Policies to determine which identities qualify for automatic access grants. Support for Conditions will expand to other areas of the Lumos platform in the future.

## Overview

A Condition is a JSON object that evaluates to `true` or `false` based on attributes of the entities being evaluated. When used in Access Policies, conditions are evaluated against identity attributes to determine if an identity qualifies for the policy. Conditions support:

* **Comparison operators**: equals, not equals, greater than, less than, etc.
* **String operators**: contains, starts with, ends with
* **Collection operators**: in, contains any
* **Logical composition**: AND, OR, NOT
* **Existence checks**: exists
* **Custom expressions**: Lumos expressions

Conditions are recursive, meaning you can nest conditions within other conditions to build complex logical expressions.

## Basic Structure

Every condition consists of:

1. **An attribute** - specifies which property of the entity to evaluate
2. **An operator** - defines how to compare or evaluate the attribute
3. **A value** (for most operators) - the value to compare against

### Simple Condition Example

```
{
  "attribute": "identity.email",
  "equals": "engineer@example.com"
}
```

This condition evaluates to `true` if the identity's email equals "[engineer@example.com](mailto:engineer@example.com)".

## Attributes

The `attribute` field specifies which property of the entity to evaluate. Attributes can be specified in two ways:

### String Attribute

A simple string path to the attribute:

```
{
  "attribute": "identity.email",
  "equals": "engineer@example.com"
}
```

Common attribute paths include:

* `identity.email` - The identity's email address
* `identity.given_name` - The identity's first name
* `identity.family_name` - The identity's last name
* `identity.full_name` - The identity's full name
* `identity.team` - The identity's team
* `identity.title` - The identity's title
* `identity.manager.uuid` - The identity's manager's UUID
* `identity.manager.email` - The identity's manager's email=
* `identity.manager.full_name` - The identity's manager's full name
* `identity.start_date` - The identity's start date
* `identity.end_date` - The identity's end date
* `identity.status` - The identity's status
* `identity.custom_attributes["Department"]` - A custom attribute named "Department"
* `identity.groups[*].external_id` - The identity's groups

### Attribute Operand

For more complex attribute selection, you can use an `AttributeOperand` object with a `label` and `value`:

```
{
  "attribute": {
    "label": "Team",
    "value": "identity.team"
  },
  "equals": "Engineering"
}
```

The `label` is a human-readable name for the attribute, while `value` is the actual path used for evaluation.

## Attribute Types

Attributes in Lumos Conditions can be of different types, each with specific behaviors and use cases.

### STRING

STRING attributes are simple text values. They work straightforwardly with string comparison operators like `equals`, `in`, `contains`, etc.

```
{
  "attribute": "identity.email",
  "equals": "engineer@example.com"
}
```

```
{
  "attribute": "identity.team",
  "equals": "Engineering"
}
```

```
{
  "attribute": "identity.custom_attributes['Department']",
  "in": ["Engineering", "Product", "Design"]
}
```

### **IDENTITY**

IDENTITY attributes represent references to other identities. When accessing IDENTITY attributes, you can reference specific properties of the identity object using dot notation.

**Direct identity relationships:**

```
{
  "attribute": "identity.manager.uuid",
  "equals": {
    "label": "Jane Smith",
    "value": "550e8400-e29b-41d4-a716-446655440000"
  }
}
```

```
{
  "attribute": "identity.manager.full_name",
  "equals": "Jane Smith"
}
```

```
{
  "attribute": "identity.manager.email",
  "equals": "jane.smith@example.com"
}
```

**Custom attributes of type IDENTITY:**

```
{
  "attribute": "identity.custom_attributes['Assistant'].uuid",
  "equals": {
    "label": "John Doe",
    "value": "550e8400-e29b-41d4-a716-446655440000"
  }
}
```

```
{
  "attribute": "identity.custom_attributes['Assistant'].full_name",
  "equals": "John Doe"
}
```

```
{
  "attribute": "identity.custom_attributes['Assistant'].email",
  "equals": "john.doe@example.com"
}
```

### GROUP

GROUP attributes represent references to groups. Groups are collections, so you typically use array notation with the `[*]` wildcard to access properties of groups in the collection.

**Accessing group external IDs:**

```
{
  "attribute": "identity.groups[*].external_id",
  "contains_any": [
    {
      "label": "Group 1",
      "value": "group-id-1"
    },
    {
      "label": "Group 2",
      "value": "group-id-2"
    }
  ]
}
```

**Excluding specific groups:**

```
{
  "attribute": "identity.groups[*].external_id",
  "not": {
    "contains_any": [
      {
        "label": "Group 1",
        "value": "group-id-1"
      },
      {
        "label": "Group 2",
        "value": "group-id-2"
      }
    ]
  }
}
```

### DATETIME

DATETIME attributes represent date and time values. When comparing DATETIME attributes, you must use ISO 8601 format strings with timezone information.

**Direct identity date fields:**

```
{
  "attribute": "identity.start_date",
  "equals": "2024-01-15T00:00:00Z"
}
```

```
{
  "attribute": "identity.start_date",
  "greater_than": "2023-01-01T00:00:00Z"
}
```

**Custom attributes of type DATETIME:**

```
{
  "attribute": "identity.custom_attributes['Hire Date']",
  "equals": "2024-01-15T00:00:00Z"
}
```

```
{
  "attribute": "identity.custom_attributes['Last Review Date']",
  "less_than": "2024-12-31T23:59:59Z"
}
```

**Expected datetime format:**

* Use ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ` or `YYYY-MM-DDTHH:MM:SS+HH:MM`
* Always include timezone information (use `Z` for UTC or offset like `+05:00` for other timezones)
* Examples:

  * `"2024-01-15T00:00:00Z"` - January 15, 2024 at midnight UTC
  * `"2024-01-15T09:00:00-08:00"` - January 15, 2024 at 9 AM PST
  * `"2024-12-31T23:59:59Z"` - December 31, 2024 at 11:59:59 PM UTC

DATETIME attributes work with comparison operators like `equals`, `greater_than`, `less_than`, `greater_than_or_equal`, and `less_than_or_equal`.

## Value Options

For better readability, you can use `ValueOption` objects instead of raw values. A `ValueOption` has a `label` (human-readable) and a `value` (the actual value used in evaluation):

```
{
  "attribute": "identity.custom_attributes['Department']",
  "equals": {
    "label": "Engineering Department",
    "value": "Engineering"
  }
}
```

This is particularly useful when the actual value might be a UUID or other non-human-readable identifier, but you want to display a friendly name in the UI.

## Supported Value Types

Condition values can be:

* **Strings**: `"Engineering"`
* **Numbers**: `42` or `3.14`
* **Booleans**: `true` or `false`
* **Dates/DateTimes**: `"2024-01-01T00:00:00Z"` (ISO 8601 format with timezone)
* **ValueOptions**: `{"label": "Friendly Name", "value": "actual_value"}`

When using dates, always use ISO 8601 format with timezone information.

## Operators

### Comparison Operators

### `equals`

Checks if the attribute equals a specific value.

```
{
  "attribute": "identity.custom_attributes['Department']",
  "equals": "Engineering"
}
```

### `!=` (Not Equal To)

Checks if the attribute does not equal a specific value.

```
{
  "attribute": "identity.custom_attributes['Department']",
  "!=": "Sales"
}
```

### `>` (Greater Than)

Checks if the attribute is greater than a value. Works with numbers and dates.

```
{
  "attribute": "identity.start_date",
  ">": "2024-01-01T00:00:00Z"
}
```

### `>=` (Greater Than or Equal To)

```
{
  "attribute": "identity.start_date",
  ">=": "2024-01-01T00:00:00Z"
}
```

### `<` (Less Than)

```
{
  "attribute": "identity.start_date",
  "<": "2024-01-01T00:00:00Z"
}
```

### `<=` (Less Than or Equal To)

```
{
  "attribute": "identity.start_date",
  "<=": "2024-01-01T00:00:00Z"
}
```

### String Operators

### `contains`

Checks if the attribute contains a substring.

```
{
  "attribute": "identity.email",
  "contains": "@engineering"
}
```

### `starts_with`

Checks if the attribute starts with a specific string.

```
{
  "attribute": "identity.email",
  "starts_with": "engineer"
}
```

### `ends_with`

Checks if the attribute ends with a specific string.

```
{
  "attribute": "identity.email",
  "ends_with": "@example.com"
}
```

### Collection Operators

### `in`

Checks if the attribute value is in a list of values. When the right-hand side is a **list**, it performs exact equality matching against each item in the list.

```
{
  "attribute": "identity.custom_attributes['Department']",
  "in": ["Engineering", "Product", "Design"]
}
```

This will match identities where the Department attribute exactly equals "Engineering", "Product", or "Design".

You can use a single string value for substring matching:

```
{
  "attribute": "identity.custom_attributes['Department']",
  "in": "Engineering Team"
}
```

This will match identities where the Department attribute is a substring of "Engineering Team". For example, if the Department is "Engineering", it would match because "Engineering" is a substring of "Engineering Team".

Important: The in operator uses Python's in operator directly. When the right-hand side is a string, it performs substring matching (not equality). When the right-hand side is a number or boolean, it will raise a TypeError and the condition will evaluate as false. For exact matching, always use an array. For example, use "in": \["Engineering"] instead of "in": "Engineering" if you want exact equality matching.

### `contains_any`

Checks if the attribute (which should be a collection) contains any of the specified values. This operator is typically used when comparing two collections.

```
{
  "attribute": "identity.groups[*].external_id",
  "contains_any": [
    {
      "label": "Engineering Team",
      "value": "eng-group-id-123"
    },
    {
      "label": "Product Team",
      "value": "product-group-id-456"
    }
  ]
}
```

### Existence Operators

### `exists`

Checks whether an attribute exists (is not null or undefined).

```
{
  "attribute": "identity.manager",
  "exists": true
}
```

To check that an attribute does NOT exist:

```
{
  "attribute": "identity.end_date",
  "exists": false
}
```

### Composition Operators

Conditions can be combined using logical operators to create complex expressions.

### `and` (AND)

Returns `true` only when all conditions in the `and` array evaluate to `true`.

```
{
  "and": [
    {
      "attribute": "identity.custom_attributes['Department']",
      "equals": "Engineering"
    },
    {
      "attribute": "identity.custom_attributes['Level']",
      "equals": "Senior"
    }
  ]
}
```

This condition is `true` only if the identity has a Department of "Engineering" AND has a Level of "Senior".

### `or` (OR)

Returns `true` when at least one condition in the `or` array evaluates to `true`.

```
{
  "or": [
    {
      "attribute": "identity.custom_attributes['Department']",
      "equals": "Engineering"
    },
    {
      "attribute": "identity.custom_attributes['Department']",
      "equals": "Product"
    }
  ]
}
```

This condition is `true` if the identity has a Department of either "Engineering" OR "Product".

### `not` (NOT)

Negates a condition. The nested condition must evaluate to `false` for the overall condition to be `true`.

```
{
  "not": {
    "attribute": "identity.custom_attributes['Department']",
    "equals": "Sales"
  }
}
```

This condition is `true` if the identity does NOT have a Department of "Sales".

### Complex Nested Conditions

You can combine all composition operators to create complex logic:

```
{
  "and": [
    {
      "or": [
        {
          "attribute": "identity.custom_attributes['Department']",
          "equals": "Engineering"
        },
        {
          "attribute": "identity.custom_attributes['Department']",
          "equals": "Product"
        }
      ]
    },
    {
      "not": {
        "attribute": "identity.status",
        "equals": "Inactive"
      }
    },
    {
      "attribute": "identity.start_date",
      ">": "2020-01-01T00:00:00Z"
    }
  ]
}
```

This condition is `true` if:

* The identity has a Department of "Engineering" OR "Product", AND
* The identity status is NOT "Inactive", AND
* The identity's Start Date is after January 1, 2020

### Advanced Operators

### `lumos_expression`

The `lumos_expression` operator allows you to use the **Lumos Expression Language (LEL)** to write complex conditional logic that goes beyond what standard condition operators can express. This is particularly useful for:

* Complex conditional logic with multiple conditions
* Data transformations and comparisons
* Fallback values and default handling
* String manipulations and transformations

**Important**: When using `lumos_expression`, you reference identity attributes using the `identity.` prefix, which is consistent with standard condition attributes.

**Standard Attributes in LEL:**

* `identity.given_name` - First name
* `identity.family_name` - Last name
* `identity.email` - Email address

**Custom Attributes in LEL:**

* `identity.custom_attributes["Attribute Name"]` - Access custom attributes

**Basic Example:**

```
{
  "lumos_expression": "identity.custom_attributes['Level'] == 'Senior' && identity.start_date > '2020-01-01'"
}
```

**Example with Conditional Logic:**

```
{
  "lumos_expression": "(identity.custom_attributes['Department'] == 'Engineering' || identity.custom_attributes['Department'] == 'Product') && identity.start_date > '2020-01-01'"
}
```

This condition checks if the identity is in Engineering or Product AND has a start date after 2020.

**Example with Fallback Values:**

```
{
  "lumos_expression": "(identity.custom_attributes['Preferred Team'] or identity.team) == 'Engineering'"
}
```

This condition checks if the identity's preferred team (if available) or default team equals "Engineering".

**Example with String Transformations:**

```
{
  "lumos_expression": "identity.email.split('@')[0].lower() == 'engineer'"
}
```

This condition checks if the email username (before the @) is "engineer" (case-insensitive).

**When to Use** `lumos_expression` **vs Standard Operators:**

* **Use standard operators** (`equals`, `in`, `and`, `or`, etc.) for simple, straightforward conditions. They're easier to read and maintain.
* **Use** `lumos_expression` when you need:

  * Complex conditional logic that's difficult to express with nested `and`/`or`/`not`
  * Data transformations (string manipulation, case conversion, etc.)
  * Fallback values or default handling
  * Calculations or comparisons that require expressions

For more information about Lumos Expression Language, including all available transformations and functions, see the [Lumos Expression Language documentation](/kb/_uncategorized/using-the-lumos-expression-language-in-workflows).

## Common Use Cases

### Access Policy: Department-Based Access

Grant access to all Engineering team members:

```
{
  "attribute": "identity.custom_attributes['Department']",
  "equals": "Engineering"
}
```

### Access Policy: Multiple Departments

Grant access to Engineering, Product, or Design:

```
{
  "or": [
    {"attribute": "identity.custom_attributes['Department']", "equals": "Engineering"},
    {"attribute": "identity.custom_attributes['Department']", "equals": "Product"},
    {"attribute": "identity.custom_attributes['Department']", "equals": "Design"}
  ]
}
```

### Access Policy: Senior Engineers Only

Grant access to senior engineers with start date after 2020:

```
{
  "and": [
    {"attribute": "identity.custom_attributes['Department']", "equals": "Engineering"},
    {"attribute": "identity.custom_attributes['Level']", "equals": "Senior"},
    {"attribute": "identity.start_date", ">": "2020-01-01T00:00:00Z"}
  ]
}
```

### Access Policy: Active Employees in Specific Teams

Grant access to active employees in specific teams:

```
{
  "and": [
    {
      "attribute": "identity.status",
      "equals": "Active"
    },
    {
      "or": [
        {
          "attribute": {
            "label": "Team",
            "value": "identity.team"
          },
          "in": ["Backend", "Frontend", "Infrastructure"]
        }
      ]
    }
  ]
}
```

### Access Policy: Direct Reports of Specific Managers

Grant access to all direct reports of specific managers:

```
{
  "attribute": {
    "label": "Manager",
    "value": "identity.manager.uuid"
  },
  "in": [
    {
      "label": "Jane Smith",
      "value": "550e8400-e29b-41d4-a716-446655440000"
    },
    {
      "label": "John Doe",
      "value": "660e8400-e29b-41d4-a716-446655440001"
    }
  ]
}
```

### Access Policy: Members of Specific Groups

Grant access to identities who are members of any of the specified groups:

```
{
  "attribute": "identity.groups[*].external_id",
  "contains_any": [
    {
      "label": "Engineering Group",
      "value": "eng-group-id-123"
    },
    {
      "label": "Product Group",
      "value": "product-group-id-456"
    }
  ]
}
```

## Using Conditions in Access Policies API

In the Lumos API, conditions are used in the `access_condition` field of Access Policies:

```
{
  "name": "Engineering Access Policy",
  "business_justification": "Automatic access for engineering team",
  "is_everyone_condition": false,
  "access_condition": {
    "attribute": "identity.custom_attributes['Department']",
    "equals": "Engineering"
  },
  "apps": [
    {
      "id": "app-uuid-here",
      "is_preapproved": true,
      "permissions": []
    }
  ]
}
```

When `is_everyone_condition` is `true`, the `access_condition` field is ignored and the policy applies to everyone.

## Error Handling

If a condition references an attribute that doesn't exist on an identity, the condition evaluation may fail or return `false` depending on the context. Always ensure your attribute paths are correct and that the identities you're evaluating have the expected structure.
