Back to all resources
ContX IQContX IQJson

ContX IQ: Filter Data Using IN Array Operator with User Subject

Query Contract nodes using the IN operator to filter by array values in policy conditions. Demonstrates how to check if a value exists within an array property during authorization.

ContX IQ: Filter Data Using IN Array Operator with User Subject

This example demonstrates using the IN operator for array-based filtering:

What is the IN operator?

The IN operator checks if a value exists within an array. Useful when authorization depends on membership in a list.

Policy pattern (two IN operands combined with AND):

- subject.external_id IN $idList (an array passed as input parameter)

- subject.external_id IN @contract.property.signers (an array property of the matched Contract node, referenced with the @ prefix)

Operations demonstrated:

1. Authenticate the user via token introspection (the policy subject is a Person, so a bearer token is required)

2. Policy checks the subject's external_id against an input array and against an array stored on the resource

3. Query returns the Contract nodes matching both filters

Use cases:

- Allow-list of subjects (check if the subject is in a list passed at execute time)

- Membership stored on the resource (check if the subject is one of the contract's signers)

- Multi-value attribute matching

Use case

Scenario: Retrieve the contracts a person accepted, but only when that person is on an allow-list and is recorded as a signer of the contract.

Graph structure:

Person(alice_sub_value) -[ACCEPTED]-> Contract(ct985) {signers: [alice_sub_value, ryan, tilda]}

Person(alice_sub_value) -[ACCEPTED]-> Contract(ct234) {signers: [alice_sub_value, ryan]}

Person(ryan) -[ACCEPTED]-> Contract(ct985), Contract(ct234)

Person(tilda) -[ACCEPTED]-> Contract(ct985), Contract(ct123) {signers: [tilda]}

Policy logic:

- The user authenticates with an access token (Person subject)

- Policy cypher: MATCH (subject:Person)-[r1:ACCEPTED]->(contract:Contract)

- Filter: subject.external_id IN $idList AND subject.external_id IN @contract.property.signers

- Only the contracts matching both array filters are returned

Query flow:

1. Execute with input_params idList = ["alice_sub_value", "ryan"]

2. Subjects alice_sub_value and ryan pass the first IN; tilda does not

3. For each of their contracts, the subject must also appear in contract.property.signers

4. Result: ct234 and ct985 are returned (ct985 once per matching subject); ct123 is not, because neither subject is among its signers

ikg

Requirements

Prerequisites:

- ServiceAccount credentials: For creating policies and queries (Bearer token)

- AppAgent credentials: For data ingestion and query execution (X-IK-ClientKey)

- User access token: JWT for the Person node to be authenticated

How to pass user token:

- Header: Authorization: Bearer {user_access_token}

- Token is introspected to identify the user and their attributes

Steps

Step 1: Ingest Graph Data

- Authentication: AppAgent credential (X-IK-ClientKey header)

- Action: POST Person nodes (alice_sub_value, ryan, tilda) and Contract nodes (ct123, ct234, ct985) whose signers property is an array, then the ACCEPTED relationships

- Result: Graph ready for array-filtered queries

Step 2: Create Policy with IN Array Filter

- Authentication: ServiceAccount credential (Bearer token)

- Action: POST policy with subject type Person, cypher MATCH (subject:Person)-[r1:ACCEPTED]->(contract:Contract), and an AND filter of:

- subject.external_id IN $idList (input parameter array)

- subject.external_id IN @contract.property.signers (array property of the contract)

- Allowed reads: contract.*, r1.*

- Result: Policy ID returned

Step 3: Create Query for Contract Properties

- Authentication: ServiceAccount credential (Bearer token)

- Action: POST query that retrieves contract.external_id, contract.property.signers and contract.property.category

- Query respects the IN array filters from the policy

- Result: Query ID returned

Step 4: Execute Query as Authenticated User

- Authentication: AppAgent credential + User token (Bearer header)

- Action: POST to /contx-iq/v1/execute with input_params idList = ["alice_sub_value", "ryan"]

- Result: ct234 and ct985 returned with their signers and category

Step 1

Capture the nodes needed for this use case.

POST https://eu.api.indykite.com/capture/v1/nodes/Json
{
  "nodes": [
    {
      "external_id": "alice_sub_value",
      "is_identity": true,
      "type": "Person",
      "properties": [
        {
          "type": "email",
          "value": "alice@email.com"
        },
        {
          "type": "given_name",
          "value": "Alice"
        },
        {
          "type": "last_name",
          "value": "Smith"
        }
      ]
    },
    {
      "external_id": "ryan",
      "is_identity": true,
      "type": "Person",
      "properties": [
        {
          "type": "email",
          "value": "ryan@yahoo.co.uk"
        },
        {
          "type": "given_name",
          "value": "ryan"
        },
        {
          "type": "last_name",
          "value": "mushu"
        }
      ]
    },
    {
      "external_id": "tilda",
      "is_identity": true,
      "type": "Person",
      "properties": [
        {
          "type": "email",
          "value": "tilda@yahoo.co.uk"
        },
        {
          "type": "given_name",
          "value": "tilda"
        },
        {
          "type": "last_name",
          "value": "mushu"
        }
      ]
    },
    {
      "external_id": "ct123",
      "type": "Contract",
      "properties": [
        {
          "type": "category",
          "value": "Insurance"
        },
        {
          "type": "status",
          "value": "Active"
        },
        {
          "type": "signers",
          "value": [
            "tilda"
          ]
        }
      ]
    },
    {
      "external_id": "ct234",
      "type": "Contract",
      "properties": [
        {
          "type": "category",
          "value": "Insurance"
        },
        {
          "type": "status",
          "value": "Active"
        },
        {
          "type": "signers",
          "value": [
            "alice_sub_value",
            "ryan"
          ]
        }
      ]
    },
    {
      "external_id": "ct985",
      "type": "Contract",
      "properties": [
        {
          "type": "category",
          "value": "Insurance"
        },
        {
          "type": "status",
          "value": "Active"
        },
        {
          "type": "signers",
          "value": [
            "alice_sub_value",
            "ryan",
            "tilda"
          ]
        }
      ]
    }
  ]
}

Capture the relationships needed for this use case.

POST https://eu.api.indykite.com/capture/v1/relationships/Json
{
  "relationships": [
    {
      "source": {
        "external_id": "alice_sub_value",
        "type": "Person"
      },
      "target": {
        "external_id": "ct985",
        "type": "Contract"
      },
      "type": "ACCEPTED"
    },
    {
      "source": {
        "external_id": "alice_sub_value",
        "type": "Person"
      },
      "target": {
        "external_id": "ct234",
        "type": "Contract"
      },
      "type": "ACCEPTED"
    },
    {
      "source": {
        "external_id": "ryan",
        "type": "Person"
      },
      "target": {
        "external_id": "ct985",
        "type": "Contract"
      },
      "type": "ACCEPTED"
    },
    {
      "source": {
        "external_id": "ryan",
        "type": "Person"
      },
      "target": {
        "external_id": "ct234",
        "type": "Contract"
      },
      "type": "ACCEPTED"
    },
    {
      "source": {
        "external_id": "tilda",
        "type": "Person"
      },
      "target": {
        "external_id": "ct985",
        "type": "Contract"
      },
      "type": "ACCEPTED"
    },
    {
      "source": {
        "external_id": "tilda",
        "type": "Person"
      },
      "target": {
        "external_id": "ct123",
        "type": "Contract"
      },
      "type": "ACCEPTED"
    }
  ]
}

Step 2

Create a CIQ Policy which designates the Subject node, the cypher, the nodes allowed to be upserted and the nodes allowed to be read.

policy.jsonJson
{
  "meta": {
    "policy_version": "1.0-ciq"
  },
  "subject": {
    "type": "Person"
  },
  "condition": {
    "cypher": "MATCH (subject:Person)-[r1:ACCEPTED]->(contract:Contract)",
    "filter": [
      {
        "app": "app1",
        "operator": "AND",
        "operands": [
          {
            "attribute": "subject.external_id",
            "operator": "IN",
            "value": "$idList"
          },
          {
            "attribute": "subject.external_id",
            "operator": "IN",
            "value": "@contract.property.signers"
          }
        ]
      }
    ]
  },
  "allowed_reads": {
    "nodes": [
      "contract.*"
    ],
    "relationships": [
      "r1.*"
    ]
  }
}

Request to create the CIQ Policy configuration using REST.

POST https://eu.api.indykite.com/configs/v1/authorization-policiesJson
{
  "project_id": "your_project_gid",
  "description": "description of policy",
  "display_name": "policy name",
  "name": "policy-name",
  "policy": "{\"meta\":{\"policy_version\":\"1.0-ciq\"},\"subject\":{\"type\":\"Person\"},\"condition\":{\"cypher\":\"MATCH (subject:Person)-[r1:ACCEPTED]->(contract:Contract)\",\"filter\":[{\"app\":\"app1\",\"operator\":\"AND\",\"operands\":[{\"attribute\":\"subject.external_id\",\"operator\":\"IN\",\"value\":\"$idList\"},{\"attribute\":\"subject.external_id\",\"operator\":\"IN\",\"value\":\"@contract.property.signers\"}]}]},\"allowed_reads\":{\"nodes\":[\"contract.*\"],\"relationships\":[\"r1.*\"]}}",
  "status": "ACTIVE",
  "tags": []
}

Request to read the CIQ Policy configuration using REST.

policy_request.jsonJson
{
  "id": "your_policy_configuration_gid"
}

Step 3

Create a CIQ Query in the context of the policy to retrieve the designated properties.

knowledge_query.jsonJson
{
  "nodes": [
    "contract.external_id",
    "contract.property.signers",
    "contract.property.category"
  ]
}

Request to create a CIQ Query configuration using REST.

POST https://eu.api.indykite.com/configs/v1/knowledge-queriesJson
{
  "project_id": "your_project_gid",
  "description": "description of knowledge query",
  "display_name": "knowledge query name",
  "name": "knowledge-query-name",
  "policy_id": "your_policy_gid",
  "query": "{\"nodes\":[\"contract.external_id\",\"contract.property.signers\",\"contract.property.category\"]}",
  "status": "ACTIVE"
}

Read the CIQ Query Configuration.

GET https://eu.api.indykite.com/configs/v1/knowledge-queries/{id}Json
{
  "id": "your_knowledge_query_configuration_gid"
}

Step 4

Run a CIQ Execution to get the designated information.

POST https://eu.api.indykite.com/contx-iq/v1/executeJson
{
  "id": "knowledge_query_gid",
  "input_params": {
    "idList": [
      "alice_sub_value",
      "ryan"
    ]
  },
  "page_token": 1
}

CIQ Execution response.

response.jsonJson
{
  "data": [
    {
      "nodes": {
        "contract.external_id": "ct234",
        "contract.property.category": "Insurance",
        "contract.property.signers": [
          "alice_sub_value",
          "ryan"
        ]
      }
    },
    {
      "nodes": {
        "contract.external_id": "ct985",
        "contract.property.category": "Insurance",
        "contract.property.signers": [
          "alice_sub_value",
          "ryan",
          "tilda"
        ]
      }
    },
    {
      "nodes": {
        "contract.external_id": "ct985",
        "contract.property.category": "Insurance",
        "contract.property.signers": [
          "alice_sub_value",
          "ryan",
          "tilda"
        ]
      }
    }
  ]
}