Back to all resources
ContX IQContX IQJson

ContX IQ: User Consent Management - Grant and Revoke Payment Access

Demonstrates user-controlled consent workflows where a Person can authorize a Company to access their payment method, and later revoke that access. Uses user tokens as subjects for self-service data governance.

ContX IQ: User Consent Management - Grant and Revoke Payment Access

This example demonstrates user-controlled consent management:

Use case: A Person grants a Company permission to charge their payment method, then later revokes it.

Key concepts:

1. User authenticates with their token -> becomes the query subject

2. User can only manage consent for their OWN payment methods

3. GRANTED relationship represents active consent

4. Deleting GRANTED relationship revokes consent

Operations:

- Grant: Create Company -[GRANTED]-> PaymentMethod relationship

- Revoke: Delete Company -[GRANTED]-> PaymentMethod relationship

This pattern supports GDPR consent requirements and user self-service.

Use case

Scenario: alice wants to let City Parking Inc (companyParking) charge her credit card (cb123) for parking.

Initial graph:

Person(alice) -[HAS]-> PaymentMethod(cb123)

Company(companyParking) -[OFFERS]-> Contract(ct123) <-[ACCEPTED]- Person(alice)

Contract(ct123) -[COVERS]-> Vehicle(car1) -[HAS]-> LicenseNumber(license1)

(bob has the same shape with kl123, ct234, car2 and license2)

Grant consent workflow:

1. alice authenticates (token introspected)

2. alice executes the grant query

3. Result: Company(companyParking) -[GRANTED]-> PaymentMethod(cb123)

Later, alice revokes consent:

1. alice authenticates again

2. alice executes the revoke query

3. Result: the GRANTED relationship is deleted

Authorization ensures:

- alice can only grant/revoke consent for HER payment methods, to a company whose contract she accepted

- The policy cypher verifies Person -[HAS]-> PaymentMethod and Company -[OFFERS]-> Contract <-[ACCEPTED]- Person

- Other users cannot modify alice's consents, because the subject is bound to the token's sub claim

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 granting/revoking consent

How to pass user token:

- Header: Authorization: Bearer {user_access_token}

- The token identifies the Person and scopes operations to their data

Steps

Step 1: Ingest Person, PaymentMethod, Contract, Vehicle, LicenseNumber and Company Data

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

- Action: POST Person (alice, bob), PaymentMethod (cb123, kl123), Contract (ct123, ct234), Vehicle (car1, car2), LicenseNumber (license1, license2) and Company (companyParking) nodes

- Action: POST HAS (Person -> PaymentMethod, Vehicle -> LicenseNumber), ACCEPTED, COVERS and OFFERS relationships

- Result: Graph ready for consent management

Step 2: Create Consent Grant Policy

- Authentication: ServiceAccount credential (Bearer token)

- Action: POST policy with subject type Person, filter subject.external_id = $token.sub, allowing the authenticated Person to:

- UPSERT a GRANTED relationship from a Company to their PaymentMethod

- Authorization path (policy cypher): Company -[OFFERS]-> Contract <-[ACCEPTED]- subject -[HAS]-> PaymentMethod, Contract -[COVERS]-> Vehicle -[HAS]-> LicenseNumber

- Result: Policy ID returned

Step 3: Create Consent Grant Query

- Authentication: ServiceAccount credential (Bearer token)

- Action: POST query that upserts company -[GRANTED]-> payment and returns company.external_id, subject.external_id and payment.external_id

- Parameters: none; the policy binds the subject to the token sub claim and the graph pattern selects the company

- Result: Query ID returned

Step 4: Execute Consent Grant (as alice)

- Authentication: AppAgent credential + alice's token (Bearer header)

- Action: POST to /contx-iq/v1/execute with empty input_params

- Result: Company(companyParking) -[GRANTED]-> PaymentMethod(cb123) created; the response returns companyParking, cb123 and alice

Step 5: Create Consent Revoke Policy

- Authentication: ServiceAccount credential (Bearer token)

- Action: POST policy with subject type Person, cypher MATCH (company:Company)-[g1:GRANTED]->(payment:PaymentMethod)<-[:HAS]-(subject:Person), filter subject.external_id = $token.sub, allowing the authenticated Person to:

- DELETE the GRANTED relationship g1 from a Company to their PaymentMethod

- Result: Policy ID returned

Step 6: Create Consent Revoke Query

- Authentication: ServiceAccount credential (Bearer token)

- Action: POST query with delete_relationships ["g1"] that also returns company.external_id, subject.external_id and payment.external_id

- Parameters: none; the policy binds the subject to the token sub claim and the graph pattern selects the relationship

- Result: Query ID returned

Step 7: Execute Consent Revoke (as alice)

- Authentication: AppAgent credential + alice's token (Bearer header)

- Action: POST to /contx-iq/v1/execute with empty input_params

- Result: Company(companyParking) -[GRANTED]-> PaymentMethod(cb123) deleted

Step 1

Capture the nodes needed for this use case.

POST https://eu.api.indykite.com/capture/v1/nodes/Json
{
  "nodes": [
    {
      "external_id": "alice",
      "is_identity": true,
      "type": "Person",
      "properties": [
        {
          "type": "email",
          "value": "alice@email.com"
        },
        {
          "type": "given_name",
          "value": "Alice"
        },
        {
          "type": "last_name",
          "value": "Smith"
        }
      ]
    },
    {
      "external_id": "bob",
      "type": "Person",
      "is_identity": true,
      "properties": [
        {
          "type": "email",
          "value": "bob@email.com"
        },
        {
          "type": "given_name",
          "value": "Bob"
        }
      ]
    },
    {
      "external_id": "cb123",
      "type": "PaymentMethod",
      "properties": [
        {
          "type": "payment_name",
          "value": "Credit Card"
        }
      ]
    },
    {
      "external_id": "kl123",
      "type": "PaymentMethod",
      "properties": [
        {
          "type": "payment_name",
          "value": "Klarna"
        }
      ]
    },
    {
      "external_id": "ct123",
      "type": "Contract",
      "properties": [
        {
          "type": "category",
          "value": "Parking"
        },
        {
          "type": "status",
          "value": "Active"
        }
      ]
    },
    {
      "external_id": "ct234",
      "type": "Contract",
      "properties": [
        {
          "type": "category",
          "value": "Parking"
        },
        {
          "type": "status",
          "value": "Active"
        }
      ]
    },
    {
      "external_id": "car1",
      "type": "Vehicle",
      "properties": [
        {
          "type": "category",
          "value": "Car"
        },
        {
          "type": "is_active",
          "value": true
        },
        {
          "type": "vin",
          "value": "rtfhcnvjt471"
        }
      ]
    },
    {
      "external_id": "car2",
      "type": "Vehicle",
      "properties": [
        {
          "type": "category",
          "value": "Car"
        },
        {
          "type": "is_active",
          "value": true
        },
        {
          "type": "vin",
          "value": "kdcbfrt178"
        }
      ]
    },
    {
      "external_id": "license1",
      "type": "LicenseNumber",
      "properties": [
        {
          "type": "status",
          "value": "Active"
        },
        {
          "type": "number",
          "value": "AX123456",
          "metadata": {
            "assurance_level": 3,
            "source": "BRREG"
          }
        }
      ]
    },
    {
      "external_id": "license2",
      "type": "LicenseNumber",
      "properties": [
        {
          "type": "status",
          "value": "Active"
        },
        {
          "type": "number",
          "value": "OL123456",
          "metadata": {
            "assurance_level": 3,
            "source": "BRREG"
          }
        }
      ]
    },
    {
      "external_id": "companyParking",
      "type": "Company",
      "properties": [
        {
          "type": "name",
          "value": "City Parking Inc"
        }
      ]
    }
  ]
}

Capture the relationships needed for this use case.

POST https://eu.api.indykite.com/capture/v1/relationships/Json
{
  "relationships": [
    {
      "source": {
        "external_id": "bob",
        "type": "Person"
      },
      "target": {
        "external_id": "kl123",
        "type": "PaymentMethod"
      },
      "type": "HAS"
    },
    {
      "source": {
        "external_id": "alice",
        "type": "Person"
      },
      "target": {
        "external_id": "cb123",
        "type": "PaymentMethod"
      },
      "type": "HAS"
    },
    {
      "source": {
        "external_id": "alice",
        "type": "Person"
      },
      "target": {
        "external_id": "ct123",
        "type": "Contract"
      },
      "type": "ACCEPTED"
    },
    {
      "source": {
        "external_id": "bob",
        "type": "Person"
      },
      "target": {
        "external_id": "ct234",
        "type": "Contract"
      },
      "type": "ACCEPTED"
    },
    {
      "source": {
        "external_id": "ct123",
        "type": "Contract"
      },
      "target": {
        "external_id": "car1",
        "type": "Vehicle"
      },
      "type": "COVERS"
    },
    {
      "source": {
        "external_id": "ct234",
        "type": "Contract"
      },
      "target": {
        "external_id": "car2",
        "type": "Vehicle"
      },
      "type": "COVERS"
    },
    {
      "source": {
        "external_id": "car1",
        "type": "Vehicle"
      },
      "target": {
        "external_id": "license1",
        "type": "LicenseNumber"
      },
      "type": "HAS"
    },
    {
      "source": {
        "external_id": "car2",
        "type": "Vehicle"
      },
      "target": {
        "external_id": "license2",
        "type": "LicenseNumber"
      },
      "type": "HAS"
    },
    {
      "source": {
        "external_id": "companyParking",
        "type": "Company"
      },
      "target": {
        "external_id": "ct234",
        "type": "Contract"
      },
      "type": "OFFERS"
    },
    {
      "source": {
        "external_id": "companyParking",
        "type": "Company"
      },
      "target": {
        "external_id": "ct123",
        "type": "Contract"
      },
      "type": "OFFERS"
    }
  ]
}

Step 2

Create a CIQ Policy which designates a relationship between a PaymentMethod and a Company can be upserted.

policy.jsonJson
{
  "meta": {
    "policy_version": "1.0-ciq"
  },
  "subject": {
    "type": "Person"
  },
  "condition": {
    "cypher": "MATCH (company:Company)-[:OFFERS]->(contract:Contract)<-[:ACCEPTED]-(subject:Person)-[:HAS]->(payment:PaymentMethod), (contract)-[:COVERS]->(vehicle:Vehicle)-[:HAS]->(ln:LicenseNumber)",
    "filter": [
      {
        "attribute": "subject.external_id",
        "operator": "=",
        "value": "$token.sub"
      }
    ]
  },
  "allowed_reads": {
    "nodes": [
      "company.*",
      "subject.*",
      "payment.*"
    ]
  },
  "allowed_upserts": {
    "relationships": {
      "relationship_types": [
        {
          "type": "GRANTED",
          "source_node_label": "Company",
          "target_node_label": "PaymentMethod"
        }
      ]
    }
  }
}

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 (company:Company)-[:OFFERS]->(contract:Contract)<-[:ACCEPTED]-(subject:Person)-[:HAS]->(payment:PaymentMethod), (contract)-[:COVERS]->(vehicle:Vehicle)-[:HAS]->(ln:LicenseNumber)\",\"filter\":[{\"attribute\":\"subject.external_id\",\"operator\":\"=\",\"value\":\"$token.sub\"}]},\"allowed_reads\":{\"nodes\":[\"company.*\",\"subject.*\",\"payment.*\"]},\"allowed_upserts\":{\"relationships\":{\"relationship_types\":[{\"type\":\"GRANTED\",\"source_node_label\":\"Company\",\"target_node_label\":\"PaymentMethod\"}]}}}",
  "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 create a GRANTED relationship between a company and a payment method.

knowledge_query.jsonJson
{
  "nodes": [
    "company.external_id",
    "subject.external_id",
    "payment.external_id"
  ],
  "upsert_relationships": [
    {
      "name": "newRel",
      "source": "company",
      "target": "payment",
      "type": "GRANTED"
    }
  ]
}

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\":[\"company.external_id\",\"subject.external_id\",\"payment.external_id\"],\"upsert_relationships\":[{\"name\":\"newRel\",\"source\":\"company\",\"target\":\"payment\",\"type\":\"GRANTED\"}]}",
  "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 create a GRANTED relationship from the Person access token.

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

CIQ Execution response.

response.jsonJson
{
  "data": [
    {
      "nodes": {
        "company.external_id": "companyParking",
        "payment.external_id": "cb123",
        "subject.external_id": "alice"
      }
    }
  ]
}

Step 5

Create a CIQ Policy which designates a relationship between a PaymentMethod and a Company can be deleted.

policy.jsonJson
{
  "meta": {
    "policy_version": "1.0-ciq"
  },
  "subject": {
    "type": "Person"
  },
  "condition": {
    "cypher": "MATCH (company:Company)-[g1:GRANTED]->(payment:PaymentMethod)<-[:HAS]-(subject:Person)",
    "filter": [
      {
        "attribute": "subject.external_id",
        "operator": "=",
        "value": "$token.sub"
      }
    ]
  },
  "allowed_reads": {
    "nodes": [
      "company.*",
      "subject.*",
      "payment.*"
    ]
  },
  "allowed_deletes": {
    "relationships": [
      "g1"
    ]
  }
}

Json 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 (company:Company)-[g1:GRANTED]->(payment:PaymentMethod)<-[:HAS]-(subject:Person)\",\"filter\":[{\"attribute\":\"subject.external_id\",\"operator\":\"=\",\"value\":\"$token.sub\"}]},\"allowed_reads\":{\"nodes\":[\"company.*\",\"subject.*\",\"payment.*\"]},\"allowed_deletes\":{\"relationships\":[\"g1\"]}}",
  "status": "ACTIVE",
  "tags": []
}

Json to read the CIQ Policy configuration using REST.

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

Step 6

Create a CIQ Query in the context of the policy to delete a GRANTED relationship between a company and a payment method.

knowledge_query.jsonJson
{
  "nodes": [
    "company.external_id",
    "subject.external_id",
    "payment.external_id"
  ],
  "delete_relationships": [
    "g1"
  ]
}

Json 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\":[\"company.external_id\",\"subject.external_id\",\"payment.external_id\"],\"delete_relationships\":[\"g1\"]}",
  "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 7

Run a CIQ Execution to delete a GRANTED relationship from the Person access token.

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

CIQ Execution response.

response.jsonJson
{
  "data": [
    {
      "nodes": {
        "company.external_id": "companyParking",
        "payment.external_id": "cb123",
        "subject.external_id": "alice"
      }
    }
  ]
}

ikg