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:
WHERE user.role IN ["admin", "manager", "viewer"]
Operations demonstrated:
1. Authenticate user via token introspection
2. Policy evaluates user attributes against allowed arrays
3. Query returns Contract nodes matching the filter criteria
Use cases:
- Role-based access (check if user role is in allowed roles list)
- Category filtering (check if item category is in permitted categories)
- Multi-value attribute matching
Use case
Scenario: Retrieve contracts that a user is authorized to view based on their roles.
Graph structure:
Person(Alice) -[ACCEPTED]-> Contract1 {type: "rental"}
Person(Alice) -[ACCEPTED]-> Contract2 {type: "lease"}
Policy logic:
- User authenticates with access token
- Token is introspected to extract user identity
- Policy filters contracts where contract.type IN ["rental", "purchase"]
- Only contracts matching the array filter are returned
Query flow:
1. User token introspected -> Person(Alice) identified
2. Policy checks Contract types against allowed array
3. Contract1 returned (type "rental" is in array)
4. Contract2 filtered out (type "lease" not in array)

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, Contract nodes and 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 filter using token introspection
- Resource filter using IN operator on array values
- Result: Policy ID returned
Step 3: Create Query for Contract Properties
- Authentication: ServiceAccount credential (Bearer token)
- Action: POST query that retrieves Contract properties
- Query respects the IN array filter 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
- Result: Contract nodes matching the array filter returned
Step 1
Capture the nodes needed for this use case.
{
"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.
{
"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.
{
"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.
{
"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.
{
"id": "your_policy_configuration_gid"
}Step 3
Create a CIQ Query in the context of the policy to retrieve the designated properties.
{
"nodes": [
"contract.external_id",
"contract.property.signers",
"contract.property.category"
]
}Request to create a CIQ Query configuration using REST.
{
"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.
{
"id": "your_knowledge_query_configuration_gid"
}Step 4
Run a CIQ Execution to get the designated information.
{
"id": "knowledge_query_gid",
"input_params": {
"idList": [
"alice_sub_value",
"ryan"
]
},
"page_token": 1
}CIQ Execution response.
{
"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_name",
"ryan",
"tilda"
]
}
},
{
"nodes": {
"contract.external_id": "ct985",
"contract.property.category": "Insurance",
"contract.property.signers": [
"alice_sub_name",
"ryan",
"tilda"
]
}
}
]
}API Endpoints
/capture/v1/nodes /capture/v1/relationships /configs/v1/authorization-policies /configs/v1/knowledge-queries /contx-iq/v1/execute