You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2026/10/04 14:29:03 UTC

(camel) branch main updated: CAMEL-25184: camel-openfga - add the readTuples, readChanges and expand operations (#27195)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new cc5a06b04130 CAMEL-25184: camel-openfga - add the readTuples, readChanges and expand operations (#27195)
cc5a06b04130 is described below

commit cc5a06b04130fad4819f1454c48302de0e20d196
Author: Andrea Cosentino <an...@gmail.com>
AuthorDate: Sun Oct 4 16:28:56 2026 +0200

    CAMEL-25184: camel-openfga - add the readTuples, readChanges and expand operations (#27195)
    
    Co-Authored-By: Claude Opus 5 <no...@anthropic.com>
---
 .../apache/camel/catalog/components/openfga.json   | 105 +++----
 .../camel/catalog/docs/openfga-component.adoc      |  87 +++++-
 .../openfga/OpenFgaComponentConfigurer.java        |  18 ++
 .../openfga/OpenFgaEndpointConfigurer.java         |  18 ++
 .../openfga/OpenFgaEndpointUriFactory.java         |   5 +-
 .../apache/camel/component/openfga/openfga.json    | 105 +++----
 .../src/main/docs/openfga-component.adoc           |  87 +++++-
 .../camel/component/openfga/OpenFgaAuthorizer.java |  28 ++
 .../component/openfga/OpenFgaConfiguration.java    |  49 ++++
 .../camel/component/openfga/OpenFgaConstants.java  |  10 +
 .../camel/component/openfga/OpenFgaEndpoint.java   |  37 ++-
 .../camel/component/openfga/OpenFgaOperation.java  |  16 ++
 .../camel/component/openfga/OpenFgaProducer.java   | 249 +++++++++++++++++
 .../apache/camel/component/openfga/OpenFgaIT.java  |  99 +++++++
 .../openfga/OpenFgaReadOperationsTest.java         | 305 +++++++++++++++++++++
 .../dsl/OpenfgaComponentBuilderFactory.java        |  59 ++++
 .../builder/endpoint/StaticEndpointBuilders.java   |  10 +-
 .../dsl/OpenFgaEndpointBuilderFactory.java         |  98 ++++++-
 18 files changed, 1271 insertions(+), 114 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openfga.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openfga.json
index 5a7bc30f1688..8530743048ce 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openfga.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openfga.json
@@ -30,31 +30,34 @@
     "configuration": { "index": 3, "kind": "property", "displayName": "Configuration", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.openfga.OpenFgaConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "The component configuration." },
     "consistency": { "index": 4, "kind": "property", "displayName": "Consistency", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "UNSPECIFIED", "MINIMIZE_LATENCY", "HIGHER_CONSISTENCY" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The consistency the query is answered with. O [...]
     "contextualTuples": { "index": 5, "kind": "property", "displayName": "Contextual Tuples", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Relationship tuples supplied for the duration of one check and never stored, as semicolon-separated u [...]
-    "lazyStartProducer": { "index": 6, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...]
-    "object": { "index": 7, "kind": "property", "displayName": "Object", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object being accessed, as an OpenFGA object identifier such as {code document:budget}. Evaluated as a Simple expressio [...]
-    "relation": { "index": 8, "kind": "property", "displayName": "Relation", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The relation to demand, such as reader or owner. Evaluated as a Simple expression against each exchange, though a lite [...]
-    "relations": { "index": 9, "kind": "property", "displayName": "Relations", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of relations the listRelations operation asks about, for example reader,writer,owner. Only the  [...]
-    "storeId": { "index": 10, "kind": "property", "displayName": "Store Id", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The identifier of the OpenFGA store holding the relationship tuples and the authorization model, [...]
-    "type": { "index": 11, "kind": "property", "displayName": "Type", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object type to enumerate for the listObjects operation, for example document. This is a type name from the authorization  [...]
-    "user": { "index": 12, "kind": "property", "displayName": "User", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The subject to authorize, as an OpenFGA user identifier such as {code user:anne}. Evaluated as a Simple expression against ea [...]
-    "userFilters": { "index": 13, "kind": "property", "displayName": "User Filters", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of user filters for the listUsers operation, naming which kinds of subject to return. An  [...]
-    "autowiredEnabled": { "index": 14, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching  [...]
-    "connectTimeout": { "index": 15, "kind": "property", "displayName": "Connect Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for the connection to OpenFGA to be established. The component a [...]
-    "maxParallelRequests": { "index": 16, "kind": "property", "displayName": "Max Parallel Requests", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many of a batchCheck's checks may be in flight at once. The batch is issu [...]
-    "maxRetries": { "index": 17, "kind": "property", "displayName": "Max Retries", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 3, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many times the SDK retries a request that failed in a way worth retrying, such as a rate limi [...]
-    "openFgaClient": { "index": 18, "kind": "property", "displayName": "Open Fga Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "dev.openfga.sdk.api.client.OpenFgaClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "An existing OpenFgaClient to use. When set, every o [...]
-    "readTimeout": { "index": 19, "kind": "property", "displayName": "Read Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for one request to OpenFGA to complete once connected. A request that  [...]
-    "healthCheckConsumerEnabled": { "index": 20, "kind": "property", "displayName": "Health Check Consumer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all consumer based health checks from this component" },
-    "healthCheckProducerEnabled": { "index": 21, "kind": "property", "displayName": "Health Check Producer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all producer based health checks from this component. Notice: Camel has by default disabled all producer based health-checks. You can turn on produce [...]
-    "apiAudience": { "index": 22, "kind": "property", "displayName": "Api Audience", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The audience to request the access token for in the client-credentials flow." },
-    "apiToken": { "index": 23, "kind": "property", "displayName": "Api Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Pre-shared token sent to OpenFGA in the Authorization header, for a server started with [...]
-    "apiTokenIssuer": { "index": 24, "kind": "property", "displayName": "Api Token Issuer", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The token endpoint the client-credentials flow exchanges its credentials at." },
-    "clientId": { "index": 25, "kind": "property", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client identifier for the OAuth 2.0 client-credentials flow, for a server that authenticates through an OIDC [...]
-    "clientSecret": { "index": 26, "kind": "property", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client secret for the OAuth 2.0 client-credentials flow." },
-    "failOpen": { "index": 27, "kind": "property", "displayName": "Fail Open", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "security": "insecure:dev", "defaultValue": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Whether to let the exchange proceed when OpenFGA could not be ask [...]
-    "scopes": { "index": 28, "kind": "property", "displayName": "Scopes", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Space-separated scopes to request in the client-credentials flow." },
-    "sslContextParameters": { "index": 29, "kind": "property", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "TLS configuration for the connection to OpenFGA.  [...]
-    "useGlobalSslContextParameters": { "index": 30, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." }
+    "continuationToken": { "index": 6, "kind": "property", "displayName": "Continuation Token", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The page to read from, for readTuples and readChanges. Evaluated as a Simple expression against the [...]
+    "lazyStartProducer": { "index": 7, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...]
+    "object": { "index": 8, "kind": "property", "displayName": "Object", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object being accessed, as an OpenFGA object identifier such as {code document:budget}. Evaluated as a Simple expressio [...]
+    "pageSize": { "index": 9, "kind": "property", "displayName": "Page Size", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many entries a readTuples or readChanges page returns. Left unset, OpenFGA's own default applies. A page is one [...]
+    "relation": { "index": 10, "kind": "property", "displayName": "Relation", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The relation to demand, such as reader or owner. Evaluated as a Simple expression against each exchange, though a lit [...]
+    "relations": { "index": 11, "kind": "property", "displayName": "Relations", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of relations the listRelations operation asks about, for example reader,writer,owner. Only the [...]
+    "startTime": { "index": 12, "kind": "property", "displayName": "Start Time", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The earliest change readChanges returns, as an ISO-8601 timestamp such as {code 2026-10-01T00:00:00Z}. Without it  [...]
+    "storeId": { "index": 13, "kind": "property", "displayName": "Store Id", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The identifier of the OpenFGA store holding the relationship tuples and the authorization model, [...]
+    "type": { "index": 14, "kind": "property", "displayName": "Type", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object type to enumerate for the listObjects operation, for example document. This is a type name from the authorization  [...]
+    "user": { "index": 15, "kind": "property", "displayName": "User", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The subject to authorize, as an OpenFGA user identifier such as {code user:anne}. Evaluated as a Simple expression against ea [...]
+    "userFilters": { "index": 16, "kind": "property", "displayName": "User Filters", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of user filters for the listUsers operation, naming which kinds of subject to return. An  [...]
+    "autowiredEnabled": { "index": 17, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching  [...]
+    "connectTimeout": { "index": 18, "kind": "property", "displayName": "Connect Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for the connection to OpenFGA to be established. The component a [...]
+    "maxParallelRequests": { "index": 19, "kind": "property", "displayName": "Max Parallel Requests", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many of a batchCheck's checks may be in flight at once. The batch is issu [...]
+    "maxRetries": { "index": 20, "kind": "property", "displayName": "Max Retries", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 3, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many times the SDK retries a request that failed in a way worth retrying, such as a rate limi [...]
+    "openFgaClient": { "index": 21, "kind": "property", "displayName": "Open Fga Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "dev.openfga.sdk.api.client.OpenFgaClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "An existing OpenFgaClient to use. When set, every o [...]
+    "readTimeout": { "index": 22, "kind": "property", "displayName": "Read Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for one request to OpenFGA to complete once connected. A request that  [...]
+    "healthCheckConsumerEnabled": { "index": 23, "kind": "property", "displayName": "Health Check Consumer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all consumer based health checks from this component" },
+    "healthCheckProducerEnabled": { "index": 24, "kind": "property", "displayName": "Health Check Producer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all producer based health checks from this component. Notice: Camel has by default disabled all producer based health-checks. You can turn on produce [...]
+    "apiAudience": { "index": 25, "kind": "property", "displayName": "Api Audience", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The audience to request the access token for in the client-credentials flow." },
+    "apiToken": { "index": 26, "kind": "property", "displayName": "Api Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Pre-shared token sent to OpenFGA in the Authorization header, for a server started with [...]
+    "apiTokenIssuer": { "index": 27, "kind": "property", "displayName": "Api Token Issuer", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The token endpoint the client-credentials flow exchanges its credentials at." },
+    "clientId": { "index": 28, "kind": "property", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client identifier for the OAuth 2.0 client-credentials flow, for a server that authenticates through an OIDC [...]
+    "clientSecret": { "index": 29, "kind": "property", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client secret for the OAuth 2.0 client-credentials flow." },
+    "failOpen": { "index": 30, "kind": "property", "displayName": "Fail Open", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "security": "insecure:dev", "defaultValue": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Whether to let the exchange proceed when OpenFGA could not be ask [...]
+    "scopes": { "index": 31, "kind": "property", "displayName": "Scopes", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Space-separated scopes to request in the client-credentials flow." },
+    "sslContextParameters": { "index": 32, "kind": "property", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "TLS configuration for the connection to OpenFGA.  [...]
+    "useGlobalSslContextParameters": { "index": 33, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." }
   },
   "headers": {
     "CamelOpenFgaAllowed": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The allow\/deny verdict of the authorization check. Always overwritten by the component, so a value set by an inbound message never survives into the route.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#ALLOWED" },
@@ -64,36 +67,40 @@
     "CamelOpenFgaObject": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The object the check was made against, as resolved from the endpoint's object expression. Set for observability; it is not read as an input.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#OBJECT" },
     "CamelOpenFgaRelation": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The relation that was checked. Set for observability; it is not read as an input and cannot be used to demand a weaker permission than the endpoint configured.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#RE [...]
     "CamelOpenFgaStoreId": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The identifier of the OpenFGA store that was consulted, so an audit trail records which relationship graph produced the verdict.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#STORE_ID" },
-    "CamelOpenFgaWrittenTuples": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "How many relationship tuples the writeTuples operation wrote.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#WRITTEN_TUPLES" },
-    "CamelOpenFgaDeletedTuples": { "index": 8, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "How many relationship tuples the deleteTuples operation deleted.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#DELETED_TUPLES" }
+    "CamelOpenFgaContinuationToken": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The continuation token the page came back with. Feed it back through the continuationToken option to read on. The two operations end differently: readTuples returns no token on its last page, so the header is absent once the [...]
+    "CamelOpenFgaWrittenTuples": { "index": 8, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "How many relationship tuples the writeTuples operation wrote.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#WRITTEN_TUPLES" },
+    "CamelOpenFgaDeletedTuples": { "index": 9, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "How many relationship tuples the deleteTuples operation deleted.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#DELETED_TUPLES" }
   },
   "properties": {
-    "operation": { "index": 0, "kind": "path", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.openfga.OpenFgaOperation", "enum": [ "check", "batchCheck", "listObjects", "listRelations", "listUsers", "writeTuples", "deleteTuples" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation to perform. The operation is taken from the endpoint only: i [...]
+    "operation": { "index": 0, "kind": "path", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.openfga.OpenFgaOperation", "enum": [ "check", "batchCheck", "listObjects", "listRelations", "listUsers", "readTuples", "readChanges", "expand", "writeTuples", "deleteTuples" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation to perform. The opera [...]
     "apiUrl": { "index": 1, "kind": "parameter", "displayName": "Api Url", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "http:\/\/localhost:8080", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The base URL of the OpenFGA HTTP API, without a trailing path. The default as [...]
     "authorizationModelId": { "index": 2, "kind": "parameter", "displayName": "Authorization Model Id", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The identifier of the authorization model revision to evaluate against. Leave it empty to u [...]
     "conditionContext": { "index": 3, "kind": "parameter", "displayName": "Condition Context", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Context passed to the CEL expressions of any conditioned relation t [...]
     "consistency": { "index": 4, "kind": "parameter", "displayName": "Consistency", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "UNSPECIFIED", "MINIMIZE_LATENCY", "HIGHER_CONSISTENCY" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The consistency the query is answered with.  [...]
     "contextualTuples": { "index": 5, "kind": "parameter", "displayName": "Contextual Tuples", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Relationship tuples supplied for the duration of one check and never stored, as semicolon-separated  [...]
-    "object": { "index": 6, "kind": "parameter", "displayName": "Object", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object being accessed, as an OpenFGA object identifier such as {code document:budget}. Evaluated as a Simple expressi [...]
-    "relation": { "index": 7, "kind": "parameter", "displayName": "Relation", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The relation to demand, such as reader or owner. Evaluated as a Simple expression against each exchange, though a lit [...]
-    "relations": { "index": 8, "kind": "parameter", "displayName": "Relations", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of relations the listRelations operation asks about, for example reader,writer,owner. Only the [...]
-    "storeId": { "index": 9, "kind": "parameter", "displayName": "Store Id", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The identifier of the OpenFGA store holding the relationship tuples and the authorization model, [...]
-    "type": { "index": 10, "kind": "parameter", "displayName": "Type", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object type to enumerate for the listObjects operation, for example document. This is a type name from the authorization [...]
-    "user": { "index": 11, "kind": "parameter", "displayName": "User", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The subject to authorize, as an OpenFGA user identifier such as {code user:anne}. Evaluated as a Simple expression against e [...]
-    "userFilters": { "index": 12, "kind": "parameter", "displayName": "User Filters", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of user filters for the listUsers operation, naming which kinds of subject to return. An [...]
-    "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...]
-    "connectTimeout": { "index": 14, "kind": "parameter", "displayName": "Connect Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for the connection to OpenFGA to be established. The component  [...]
-    "maxParallelRequests": { "index": 15, "kind": "parameter", "displayName": "Max Parallel Requests", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many of a batchCheck's checks may be in flight at once. The batch is iss [...]
-    "maxRetries": { "index": 16, "kind": "parameter", "displayName": "Max Retries", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 3, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many times the SDK retries a request that failed in a way worth retrying, such as a rate lim [...]
-    "openFgaClient": { "index": 17, "kind": "parameter", "displayName": "Open Fga Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "dev.openfga.sdk.api.client.OpenFgaClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "An existing OpenFgaClient to use. When set, every  [...]
-    "readTimeout": { "index": 18, "kind": "parameter", "displayName": "Read Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for one request to OpenFGA to complete once connected. A request that [...]
-    "apiAudience": { "index": 19, "kind": "parameter", "displayName": "Api Audience", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The audience to request the access token for in the client-credentials flow." },
-    "apiToken": { "index": 20, "kind": "parameter", "displayName": "Api Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Pre-shared token sent to OpenFGA in the Authorization header, for a server started wit [...]
-    "apiTokenIssuer": { "index": 21, "kind": "parameter", "displayName": "Api Token Issuer", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The token endpoint the client-credentials flow exchanges its credentials at." },
-    "clientId": { "index": 22, "kind": "parameter", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client identifier for the OAuth 2.0 client-credentials flow, for a server that authenticates through an OID [...]
-    "clientSecret": { "index": 23, "kind": "parameter", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client secret for the OAuth 2.0 client-credentials flow." },
-    "failOpen": { "index": 24, "kind": "parameter", "displayName": "Fail Open", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "security": "insecure:dev", "defaultValue": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Whether to let the exchange proceed when OpenFGA could not be as [...]
-    "scopes": { "index": 25, "kind": "parameter", "displayName": "Scopes", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Space-separated scopes to request in the client-credentials flow." },
-    "sslContextParameters": { "index": 26, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "TLS configuration for the connection to OpenFGA. [...]
+    "continuationToken": { "index": 6, "kind": "parameter", "displayName": "Continuation Token", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The page to read from, for readTuples and readChanges. Evaluated as a Simple expression against th [...]
+    "object": { "index": 7, "kind": "parameter", "displayName": "Object", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object being accessed, as an OpenFGA object identifier such as {code document:budget}. Evaluated as a Simple expressi [...]
+    "pageSize": { "index": 8, "kind": "parameter", "displayName": "Page Size", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many entries a readTuples or readChanges page returns. Left unset, OpenFGA's own default applies. A page is on [...]
+    "relation": { "index": 9, "kind": "parameter", "displayName": "Relation", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The relation to demand, such as reader or owner. Evaluated as a Simple expression against each exchange, though a lit [...]
+    "relations": { "index": 10, "kind": "parameter", "displayName": "Relations", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of relations the listRelations operation asks about, for example reader,writer,owner. Only th [...]
+    "startTime": { "index": 11, "kind": "parameter", "displayName": "Start Time", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The earliest change readChanges returns, as an ISO-8601 timestamp such as {code 2026-10-01T00:00:00Z}. Without it [...]
+    "storeId": { "index": 12, "kind": "parameter", "displayName": "Store Id", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The identifier of the OpenFGA store holding the relationship tuples and the authorization model [...]
+    "type": { "index": 13, "kind": "parameter", "displayName": "Type", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object type to enumerate for the listObjects operation, for example document. This is a type name from the authorization [...]
+    "user": { "index": 14, "kind": "parameter", "displayName": "User", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The subject to authorize, as an OpenFGA user identifier such as {code user:anne}. Evaluated as a Simple expression against e [...]
+    "userFilters": { "index": 15, "kind": "parameter", "displayName": "User Filters", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of user filters for the listUsers operation, naming which kinds of subject to return. An [...]
+    "lazyStartProducer": { "index": 16, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...]
+    "connectTimeout": { "index": 17, "kind": "parameter", "displayName": "Connect Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for the connection to OpenFGA to be established. The component  [...]
+    "maxParallelRequests": { "index": 18, "kind": "parameter", "displayName": "Max Parallel Requests", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many of a batchCheck's checks may be in flight at once. The batch is iss [...]
+    "maxRetries": { "index": 19, "kind": "parameter", "displayName": "Max Retries", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 3, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many times the SDK retries a request that failed in a way worth retrying, such as a rate lim [...]
+    "openFgaClient": { "index": 20, "kind": "parameter", "displayName": "Open Fga Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "dev.openfga.sdk.api.client.OpenFgaClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "An existing OpenFgaClient to use. When set, every  [...]
+    "readTimeout": { "index": 21, "kind": "parameter", "displayName": "Read Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for one request to OpenFGA to complete once connected. A request that [...]
+    "apiAudience": { "index": 22, "kind": "parameter", "displayName": "Api Audience", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The audience to request the access token for in the client-credentials flow." },
+    "apiToken": { "index": 23, "kind": "parameter", "displayName": "Api Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Pre-shared token sent to OpenFGA in the Authorization header, for a server started wit [...]
+    "apiTokenIssuer": { "index": 24, "kind": "parameter", "displayName": "Api Token Issuer", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The token endpoint the client-credentials flow exchanges its credentials at." },
+    "clientId": { "index": 25, "kind": "parameter", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client identifier for the OAuth 2.0 client-credentials flow, for a server that authenticates through an OID [...]
+    "clientSecret": { "index": 26, "kind": "parameter", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client secret for the OAuth 2.0 client-credentials flow." },
+    "failOpen": { "index": 27, "kind": "parameter", "displayName": "Fail Open", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "security": "insecure:dev", "defaultValue": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Whether to let the exchange proceed when OpenFGA could not be as [...]
+    "scopes": { "index": 28, "kind": "parameter", "displayName": "Scopes", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Space-separated scopes to request in the client-credentials flow." },
+    "sslContextParameters": { "index": 29, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "TLS configuration for the connection to OpenFGA. [...]
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfga-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfga-component.adoc
index f7c91f578588..00067a8708c6 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfga-component.adoc
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openfga-component.adoc
@@ -52,8 +52,8 @@ Maven users will need to add the following dependency to their `pom.xml`.
 openfga:operation[?options]
 ------------------------------------------------------------
 
-Where `operation` is one of `check`, `batchCheck`, `listObjects`, `listRelations`, `listUsers`, `writeTuples` or
-`deleteTuples`.
+Where `operation` is one of `check`, `batchCheck`, `listObjects`, `listRelations`, `listUsers`, `readTuples`,
+`readChanges`, `expand`, `writeTuples` or `deleteTuples`.
 
 // component options: START
 include::partial$component-configure-options.adoc[]
@@ -383,9 +383,90 @@ stricter, but it would silently answer a different question than the endpoint wa
 Contextual tuples supplied by the *message* are deliberately not supported. If you need them, the tuple has to come
 from somewhere the caller cannot reach, which in practice means the endpoint.
 
+=== Reading the graph
+
+`readTuples` answers "what access exists", as opposed to `check`'s "may this subject do this". Here `user`, `relation`
+and `object` are a *filter* rather than a subject, and the body comes back as a list of maps keyed `user`, `relation`,
+`object` and `timestamp` — deliberately the keys `writeTuples` and `deleteTuples` accept, so a route can revoke what
+it just read without reshaping anything:
+
+[source,java]
+------------------------------------------------------------
+from("direct:revokeEverythingBobHas")
+        .to("openfga:readTuples?storeId={{fga.store}}&object=document:&user=user:bob")
+        .to("openfga:deleteTuples?storeId={{fga.store}}");
+------------------------------------------------------------
+
+[NOTE]
+.What OpenFGA accepts as a read filter
+====
+The filter is narrower than "every part is optional". Measured against OpenFGA 1.21.0:
+
+* no filter at all — reads the whole store, a page at a time;
+* `object=document:` *plus* a `user` — reads that user's tuples of that object type;
+* `object=document:budget` — reads that object's tuples, with or without a user or relation;
+* `user` alone, `relation` alone, or `object=document:` alone — **rejected**, because OpenFGA requires an object type
+  as soon as any filter is given and will not accept an empty object id and an empty user together.
+
+The component checks this before the call and names the option to change, rather than letting an opaque HTTP 400
+through. Note this is also why a type-only `document:` is accepted here but not as an `object` anywhere else: a read
+filter and an identifier have different rules.
+
+What "optional" does *not* mean is that a part may go missing at runtime. Only an option the endpoint never set counts
+as "do not filter on this"; an option that *is* set and evaluates to nothing — `user=${header.who}` on a message with
+no `who` header — is refused. Dropping it would make the read wider than the route asked for, and with the
+`readTuples` -> `deleteTuples` route above that turns "revoke Bob's access" into "revoke everyone's". A filter that
+silently widens when a value goes missing is the read-side form of failing open.
+====
+
+`readChanges` reads the change log, which is the building block for keeping a cache or a projection in step with the
+graph. Each entry adds an `operation` of `WRITE` or `DELETE`.
+
+Both are paged. `pageSize` bounds one request, and the token the page returns arrives on
+`CamelOpenFgaContinuationToken`; feed it back through `continuationToken` to read on.
+
+A `readChanges` poller has to carry that token from one exchange to the *next*, which an exchange property cannot do:
+every timer fire is a new exchange, so a property left on the previous one is gone and each poll would start from the
+beginning again. Use a global variable, which outlives the exchange:
+
+[source,java]
+------------------------------------------------------------
+from("timer:sync?period=30000")
+        .to("openfga:readChanges?storeId={{fga.store}}&type=document"
+            + "&continuationToken=${variable.global:fgaToken}")
+        .setVariable("global:fgaToken", header("CamelOpenFgaContinuationToken"))
+        .split(body()).to("direct:applyChange");
+------------------------------------------------------------
+
+A global variable lives in the `CamelContext`, so it does not survive a restart. A poller that must resume across one
+should keep the token wherever the deployment already persists state rather than rely on it.
+
+`startTime` bounds where a first read begins — without it a first `readChanges` on a busy store pages through the whole
+history before reaching anything current.
+
+[IMPORTANT]
+.The two read operations signal "done" differently
+====
+Measured against OpenFGA 1.21.0, not assumed:
+
+* `readTuples` returns no token on its last page, so `CamelOpenFgaContinuationToken` is **absent** once the read is
+  finished. Looping until the header is missing is the right way to drain it.
+* `readChanges` returns a token **every** time, including when nothing has happened — it hands the token you sent
+  straight back with an empty page. Looping until the header is missing would therefore never end. The signal there is
+  an **empty body**, and the token it keeps returning is the bookmark the next poll resumes from, which is why the
+  component leaves it in place instead of clearing it.
+====
+
+`expand` is the odd one out: it is the only operation that does not leave a `List` on the body, because its answer is
+a tree of usersets rather than a list. The `UsersetTree` goes on the body as the SDK returns it — flattening it is
+exactly what would destroy the information the operation exists to provide. Reach for it when a check answered
+something surprising and you need to see how it got there.
+
 == What this component does not do yet
 
-* The `expand`, `readTuples` and `readChanges` operations, and store or authorization-model management.
+* Store and authorization-model management — `createStore`, `deleteStore`, `writeAuthorizationModel` and the rest.
+  These are administrative rather than integration operations, and a component that can delete the store it
+  authorizes against is a different proposition from one that can only ask it questions.
 
 == Examples
 
diff --git a/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaComponentConfigurer.java b/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaComponentConfigurer.java
index 1498cf4e0888..e837a76ae5db 100644
--- a/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaComponentConfigurer.java
+++ b/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaComponentConfigurer.java
@@ -54,6 +54,8 @@ public class OpenFgaComponentConfigurer extends PropertyConfigurerSupport implem
         case "consistency": getOrCreateConfiguration(target).setConsistency(property(camelContext, java.lang.String.class, value)); return true;
         case "contextualtuples":
         case "contextualTuples": getOrCreateConfiguration(target).setContextualTuples(property(camelContext, java.lang.String.class, value)); return true;
+        case "continuationtoken":
+        case "continuationToken": getOrCreateConfiguration(target).setContinuationToken(property(camelContext, java.lang.String.class, value)); return true;
         case "failopen":
         case "failOpen": getOrCreateConfiguration(target).setFailOpen(property(camelContext, boolean.class, value)); return true;
         case "healthcheckconsumerenabled":
@@ -69,6 +71,8 @@ public class OpenFgaComponentConfigurer extends PropertyConfigurerSupport implem
         case "object": getOrCreateConfiguration(target).setObject(property(camelContext, java.lang.String.class, value)); return true;
         case "openfgaclient":
         case "openFgaClient": getOrCreateConfiguration(target).setOpenFgaClient(property(camelContext, dev.openfga.sdk.api.client.OpenFgaClient.class, value)); return true;
+        case "pagesize":
+        case "pageSize": getOrCreateConfiguration(target).setPageSize(property(camelContext, java.lang.Integer.class, value)); return true;
         case "readtimeout":
         case "readTimeout": getOrCreateConfiguration(target).setReadTimeout(property(camelContext, java.time.Duration.class, value).toMillis()); return true;
         case "relation": getOrCreateConfiguration(target).setRelation(property(camelContext, java.lang.String.class, value)); return true;
@@ -76,6 +80,8 @@ public class OpenFgaComponentConfigurer extends PropertyConfigurerSupport implem
         case "scopes": getOrCreateConfiguration(target).setScopes(property(camelContext, java.lang.String.class, value)); return true;
         case "sslcontextparameters":
         case "sslContextParameters": getOrCreateConfiguration(target).setSslContextParameters(property(camelContext, org.apache.camel.support.jsse.SSLContextParameters.class, value)); return true;
+        case "starttime":
+        case "startTime": getOrCreateConfiguration(target).setStartTime(property(camelContext, java.lang.String.class, value)); return true;
         case "storeid":
         case "storeId": getOrCreateConfiguration(target).setStoreId(property(camelContext, java.lang.String.class, value)); return true;
         case "type": getOrCreateConfiguration(target).setType(property(camelContext, java.lang.String.class, value)); return true;
@@ -120,6 +126,8 @@ public class OpenFgaComponentConfigurer extends PropertyConfigurerSupport implem
         case "consistency": return java.lang.String.class;
         case "contextualtuples":
         case "contextualTuples": return java.lang.String.class;
+        case "continuationtoken":
+        case "continuationToken": return java.lang.String.class;
         case "failopen":
         case "failOpen": return boolean.class;
         case "healthcheckconsumerenabled":
@@ -135,6 +143,8 @@ public class OpenFgaComponentConfigurer extends PropertyConfigurerSupport implem
         case "object": return java.lang.String.class;
         case "openfgaclient":
         case "openFgaClient": return dev.openfga.sdk.api.client.OpenFgaClient.class;
+        case "pagesize":
+        case "pageSize": return java.lang.Integer.class;
         case "readtimeout":
         case "readTimeout": return long.class;
         case "relation": return java.lang.String.class;
@@ -142,6 +152,8 @@ public class OpenFgaComponentConfigurer extends PropertyConfigurerSupport implem
         case "scopes": return java.lang.String.class;
         case "sslcontextparameters":
         case "sslContextParameters": return org.apache.camel.support.jsse.SSLContextParameters.class;
+        case "starttime":
+        case "startTime": return java.lang.String.class;
         case "storeid":
         case "storeId": return java.lang.String.class;
         case "type": return java.lang.String.class;
@@ -182,6 +194,8 @@ public class OpenFgaComponentConfigurer extends PropertyConfigurerSupport implem
         case "consistency": return getOrCreateConfiguration(target).getConsistency();
         case "contextualtuples":
         case "contextualTuples": return getOrCreateConfiguration(target).getContextualTuples();
+        case "continuationtoken":
+        case "continuationToken": return getOrCreateConfiguration(target).getContinuationToken();
         case "failopen":
         case "failOpen": return getOrCreateConfiguration(target).isFailOpen();
         case "healthcheckconsumerenabled":
@@ -197,6 +211,8 @@ public class OpenFgaComponentConfigurer extends PropertyConfigurerSupport implem
         case "object": return getOrCreateConfiguration(target).getObject();
         case "openfgaclient":
         case "openFgaClient": return getOrCreateConfiguration(target).getOpenFgaClient();
+        case "pagesize":
+        case "pageSize": return getOrCreateConfiguration(target).getPageSize();
         case "readtimeout":
         case "readTimeout": return getOrCreateConfiguration(target).getReadTimeout();
         case "relation": return getOrCreateConfiguration(target).getRelation();
@@ -204,6 +220,8 @@ public class OpenFgaComponentConfigurer extends PropertyConfigurerSupport implem
         case "scopes": return getOrCreateConfiguration(target).getScopes();
         case "sslcontextparameters":
         case "sslContextParameters": return getOrCreateConfiguration(target).getSslContextParameters();
+        case "starttime":
+        case "startTime": return getOrCreateConfiguration(target).getStartTime();
         case "storeid":
         case "storeId": return getOrCreateConfiguration(target).getStoreId();
         case "type": return getOrCreateConfiguration(target).getType();
diff --git a/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaEndpointConfigurer.java b/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaEndpointConfigurer.java
index 5a700f40e83d..ec6009c86e61 100644
--- a/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaEndpointConfigurer.java
+++ b/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaEndpointConfigurer.java
@@ -44,6 +44,8 @@ public class OpenFgaEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "consistency": target.getConfiguration().setConsistency(property(camelContext, java.lang.String.class, value)); return true;
         case "contextualtuples":
         case "contextualTuples": target.getConfiguration().setContextualTuples(property(camelContext, java.lang.String.class, value)); return true;
+        case "continuationtoken":
+        case "continuationToken": target.getConfiguration().setContinuationToken(property(camelContext, java.lang.String.class, value)); return true;
         case "failopen":
         case "failOpen": target.getConfiguration().setFailOpen(property(camelContext, boolean.class, value)); return true;
         case "lazystartproducer":
@@ -55,6 +57,8 @@ public class OpenFgaEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "object": target.getConfiguration().setObject(property(camelContext, java.lang.String.class, value)); return true;
         case "openfgaclient":
         case "openFgaClient": target.getConfiguration().setOpenFgaClient(property(camelContext, dev.openfga.sdk.api.client.OpenFgaClient.class, value)); return true;
+        case "pagesize":
+        case "pageSize": target.getConfiguration().setPageSize(property(camelContext, java.lang.Integer.class, value)); return true;
         case "readtimeout":
         case "readTimeout": target.getConfiguration().setReadTimeout(property(camelContext, java.time.Duration.class, value).toMillis()); return true;
         case "relation": target.getConfiguration().setRelation(property(camelContext, java.lang.String.class, value)); return true;
@@ -62,6 +66,8 @@ public class OpenFgaEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "scopes": target.getConfiguration().setScopes(property(camelContext, java.lang.String.class, value)); return true;
         case "sslcontextparameters":
         case "sslContextParameters": target.getConfiguration().setSslContextParameters(property(camelContext, org.apache.camel.support.jsse.SSLContextParameters.class, value)); return true;
+        case "starttime":
+        case "startTime": target.getConfiguration().setStartTime(property(camelContext, java.lang.String.class, value)); return true;
         case "storeid":
         case "storeId": target.getConfiguration().setStoreId(property(camelContext, java.lang.String.class, value)); return true;
         case "type": target.getConfiguration().setType(property(camelContext, java.lang.String.class, value)); return true;
@@ -101,6 +107,8 @@ public class OpenFgaEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "consistency": return java.lang.String.class;
         case "contextualtuples":
         case "contextualTuples": return java.lang.String.class;
+        case "continuationtoken":
+        case "continuationToken": return java.lang.String.class;
         case "failopen":
         case "failOpen": return boolean.class;
         case "lazystartproducer":
@@ -112,6 +120,8 @@ public class OpenFgaEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "object": return java.lang.String.class;
         case "openfgaclient":
         case "openFgaClient": return dev.openfga.sdk.api.client.OpenFgaClient.class;
+        case "pagesize":
+        case "pageSize": return java.lang.Integer.class;
         case "readtimeout":
         case "readTimeout": return long.class;
         case "relation": return java.lang.String.class;
@@ -119,6 +129,8 @@ public class OpenFgaEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "scopes": return java.lang.String.class;
         case "sslcontextparameters":
         case "sslContextParameters": return org.apache.camel.support.jsse.SSLContextParameters.class;
+        case "starttime":
+        case "startTime": return java.lang.String.class;
         case "storeid":
         case "storeId": return java.lang.String.class;
         case "type": return java.lang.String.class;
@@ -154,6 +166,8 @@ public class OpenFgaEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "consistency": return target.getConfiguration().getConsistency();
         case "contextualtuples":
         case "contextualTuples": return target.getConfiguration().getContextualTuples();
+        case "continuationtoken":
+        case "continuationToken": return target.getConfiguration().getContinuationToken();
         case "failopen":
         case "failOpen": return target.getConfiguration().isFailOpen();
         case "lazystartproducer":
@@ -165,6 +179,8 @@ public class OpenFgaEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "object": return target.getConfiguration().getObject();
         case "openfgaclient":
         case "openFgaClient": return target.getConfiguration().getOpenFgaClient();
+        case "pagesize":
+        case "pageSize": return target.getConfiguration().getPageSize();
         case "readtimeout":
         case "readTimeout": return target.getConfiguration().getReadTimeout();
         case "relation": return target.getConfiguration().getRelation();
@@ -172,6 +188,8 @@ public class OpenFgaEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "scopes": return target.getConfiguration().getScopes();
         case "sslcontextparameters":
         case "sslContextParameters": return target.getConfiguration().getSslContextParameters();
+        case "starttime":
+        case "startTime": return target.getConfiguration().getStartTime();
         case "storeid":
         case "storeId": return target.getConfiguration().getStoreId();
         case "type": return target.getConfiguration().getType();
diff --git a/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaEndpointUriFactory.java b/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaEndpointUriFactory.java
index 239cabd3832e..baf28a461248 100644
--- a/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaEndpointUriFactory.java
+++ b/components/camel-openfga/src/generated/java/org/apache/camel/component/openfga/OpenFgaEndpointUriFactory.java
@@ -24,7 +24,7 @@ public class OpenFgaEndpointUriFactory extends org.apache.camel.support.componen
     private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(27);
+        Set<String> props = new HashSet<>(30);
         props.add("apiAudience");
         props.add("apiToken");
         props.add("apiTokenIssuer");
@@ -36,6 +36,7 @@ public class OpenFgaEndpointUriFactory extends org.apache.camel.support.componen
         props.add("connectTimeout");
         props.add("consistency");
         props.add("contextualTuples");
+        props.add("continuationToken");
         props.add("failOpen");
         props.add("lazyStartProducer");
         props.add("maxParallelRequests");
@@ -43,11 +44,13 @@ public class OpenFgaEndpointUriFactory extends org.apache.camel.support.componen
         props.add("object");
         props.add("openFgaClient");
         props.add("operation");
+        props.add("pageSize");
         props.add("readTimeout");
         props.add("relation");
         props.add("relations");
         props.add("scopes");
         props.add("sslContextParameters");
+        props.add("startTime");
         props.add("storeId");
         props.add("type");
         props.add("user");
diff --git a/components/camel-openfga/src/generated/resources/META-INF/org/apache/camel/component/openfga/openfga.json b/components/camel-openfga/src/generated/resources/META-INF/org/apache/camel/component/openfga/openfga.json
index 5a7bc30f1688..8530743048ce 100644
--- a/components/camel-openfga/src/generated/resources/META-INF/org/apache/camel/component/openfga/openfga.json
+++ b/components/camel-openfga/src/generated/resources/META-INF/org/apache/camel/component/openfga/openfga.json
@@ -30,31 +30,34 @@
     "configuration": { "index": 3, "kind": "property", "displayName": "Configuration", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.openfga.OpenFgaConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "The component configuration." },
     "consistency": { "index": 4, "kind": "property", "displayName": "Consistency", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "UNSPECIFIED", "MINIMIZE_LATENCY", "HIGHER_CONSISTENCY" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The consistency the query is answered with. O [...]
     "contextualTuples": { "index": 5, "kind": "property", "displayName": "Contextual Tuples", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Relationship tuples supplied for the duration of one check and never stored, as semicolon-separated u [...]
-    "lazyStartProducer": { "index": 6, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...]
-    "object": { "index": 7, "kind": "property", "displayName": "Object", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object being accessed, as an OpenFGA object identifier such as {code document:budget}. Evaluated as a Simple expressio [...]
-    "relation": { "index": 8, "kind": "property", "displayName": "Relation", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The relation to demand, such as reader or owner. Evaluated as a Simple expression against each exchange, though a lite [...]
-    "relations": { "index": 9, "kind": "property", "displayName": "Relations", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of relations the listRelations operation asks about, for example reader,writer,owner. Only the  [...]
-    "storeId": { "index": 10, "kind": "property", "displayName": "Store Id", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The identifier of the OpenFGA store holding the relationship tuples and the authorization model, [...]
-    "type": { "index": 11, "kind": "property", "displayName": "Type", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object type to enumerate for the listObjects operation, for example document. This is a type name from the authorization  [...]
-    "user": { "index": 12, "kind": "property", "displayName": "User", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The subject to authorize, as an OpenFGA user identifier such as {code user:anne}. Evaluated as a Simple expression against ea [...]
-    "userFilters": { "index": 13, "kind": "property", "displayName": "User Filters", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of user filters for the listUsers operation, naming which kinds of subject to return. An  [...]
-    "autowiredEnabled": { "index": 14, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching  [...]
-    "connectTimeout": { "index": 15, "kind": "property", "displayName": "Connect Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for the connection to OpenFGA to be established. The component a [...]
-    "maxParallelRequests": { "index": 16, "kind": "property", "displayName": "Max Parallel Requests", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many of a batchCheck's checks may be in flight at once. The batch is issu [...]
-    "maxRetries": { "index": 17, "kind": "property", "displayName": "Max Retries", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 3, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many times the SDK retries a request that failed in a way worth retrying, such as a rate limi [...]
-    "openFgaClient": { "index": 18, "kind": "property", "displayName": "Open Fga Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "dev.openfga.sdk.api.client.OpenFgaClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "An existing OpenFgaClient to use. When set, every o [...]
-    "readTimeout": { "index": 19, "kind": "property", "displayName": "Read Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for one request to OpenFGA to complete once connected. A request that  [...]
-    "healthCheckConsumerEnabled": { "index": 20, "kind": "property", "displayName": "Health Check Consumer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all consumer based health checks from this component" },
-    "healthCheckProducerEnabled": { "index": 21, "kind": "property", "displayName": "Health Check Producer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all producer based health checks from this component. Notice: Camel has by default disabled all producer based health-checks. You can turn on produce [...]
-    "apiAudience": { "index": 22, "kind": "property", "displayName": "Api Audience", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The audience to request the access token for in the client-credentials flow." },
-    "apiToken": { "index": 23, "kind": "property", "displayName": "Api Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Pre-shared token sent to OpenFGA in the Authorization header, for a server started with [...]
-    "apiTokenIssuer": { "index": 24, "kind": "property", "displayName": "Api Token Issuer", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The token endpoint the client-credentials flow exchanges its credentials at." },
-    "clientId": { "index": 25, "kind": "property", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client identifier for the OAuth 2.0 client-credentials flow, for a server that authenticates through an OIDC [...]
-    "clientSecret": { "index": 26, "kind": "property", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client secret for the OAuth 2.0 client-credentials flow." },
-    "failOpen": { "index": 27, "kind": "property", "displayName": "Fail Open", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "security": "insecure:dev", "defaultValue": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Whether to let the exchange proceed when OpenFGA could not be ask [...]
-    "scopes": { "index": 28, "kind": "property", "displayName": "Scopes", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Space-separated scopes to request in the client-credentials flow." },
-    "sslContextParameters": { "index": 29, "kind": "property", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "TLS configuration for the connection to OpenFGA.  [...]
-    "useGlobalSslContextParameters": { "index": 30, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." }
+    "continuationToken": { "index": 6, "kind": "property", "displayName": "Continuation Token", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The page to read from, for readTuples and readChanges. Evaluated as a Simple expression against the [...]
+    "lazyStartProducer": { "index": 7, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...]
+    "object": { "index": 8, "kind": "property", "displayName": "Object", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object being accessed, as an OpenFGA object identifier such as {code document:budget}. Evaluated as a Simple expressio [...]
+    "pageSize": { "index": 9, "kind": "property", "displayName": "Page Size", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many entries a readTuples or readChanges page returns. Left unset, OpenFGA's own default applies. A page is one [...]
+    "relation": { "index": 10, "kind": "property", "displayName": "Relation", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The relation to demand, such as reader or owner. Evaluated as a Simple expression against each exchange, though a lit [...]
+    "relations": { "index": 11, "kind": "property", "displayName": "Relations", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of relations the listRelations operation asks about, for example reader,writer,owner. Only the [...]
+    "startTime": { "index": 12, "kind": "property", "displayName": "Start Time", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The earliest change readChanges returns, as an ISO-8601 timestamp such as {code 2026-10-01T00:00:00Z}. Without it  [...]
+    "storeId": { "index": 13, "kind": "property", "displayName": "Store Id", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The identifier of the OpenFGA store holding the relationship tuples and the authorization model, [...]
+    "type": { "index": 14, "kind": "property", "displayName": "Type", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object type to enumerate for the listObjects operation, for example document. This is a type name from the authorization  [...]
+    "user": { "index": 15, "kind": "property", "displayName": "User", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The subject to authorize, as an OpenFGA user identifier such as {code user:anne}. Evaluated as a Simple expression against ea [...]
+    "userFilters": { "index": 16, "kind": "property", "displayName": "User Filters", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of user filters for the listUsers operation, naming which kinds of subject to return. An  [...]
+    "autowiredEnabled": { "index": 17, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching  [...]
+    "connectTimeout": { "index": 18, "kind": "property", "displayName": "Connect Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for the connection to OpenFGA to be established. The component a [...]
+    "maxParallelRequests": { "index": 19, "kind": "property", "displayName": "Max Parallel Requests", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many of a batchCheck's checks may be in flight at once. The batch is issu [...]
+    "maxRetries": { "index": 20, "kind": "property", "displayName": "Max Retries", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 3, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many times the SDK retries a request that failed in a way worth retrying, such as a rate limi [...]
+    "openFgaClient": { "index": 21, "kind": "property", "displayName": "Open Fga Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "dev.openfga.sdk.api.client.OpenFgaClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "An existing OpenFgaClient to use. When set, every o [...]
+    "readTimeout": { "index": 22, "kind": "property", "displayName": "Read Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for one request to OpenFGA to complete once connected. A request that  [...]
+    "healthCheckConsumerEnabled": { "index": 23, "kind": "property", "displayName": "Health Check Consumer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all consumer based health checks from this component" },
+    "healthCheckProducerEnabled": { "index": 24, "kind": "property", "displayName": "Health Check Producer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all producer based health checks from this component. Notice: Camel has by default disabled all producer based health-checks. You can turn on produce [...]
+    "apiAudience": { "index": 25, "kind": "property", "displayName": "Api Audience", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The audience to request the access token for in the client-credentials flow." },
+    "apiToken": { "index": 26, "kind": "property", "displayName": "Api Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Pre-shared token sent to OpenFGA in the Authorization header, for a server started with [...]
+    "apiTokenIssuer": { "index": 27, "kind": "property", "displayName": "Api Token Issuer", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The token endpoint the client-credentials flow exchanges its credentials at." },
+    "clientId": { "index": 28, "kind": "property", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client identifier for the OAuth 2.0 client-credentials flow, for a server that authenticates through an OIDC [...]
+    "clientSecret": { "index": 29, "kind": "property", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client secret for the OAuth 2.0 client-credentials flow." },
+    "failOpen": { "index": 30, "kind": "property", "displayName": "Fail Open", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "security": "insecure:dev", "defaultValue": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Whether to let the exchange proceed when OpenFGA could not be ask [...]
+    "scopes": { "index": 31, "kind": "property", "displayName": "Scopes", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Space-separated scopes to request in the client-credentials flow." },
+    "sslContextParameters": { "index": 32, "kind": "property", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "TLS configuration for the connection to OpenFGA.  [...]
+    "useGlobalSslContextParameters": { "index": 33, "kind": "property", "displayName": "Use Global Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Enable usage of global SSL context parameters." }
   },
   "headers": {
     "CamelOpenFgaAllowed": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The allow\/deny verdict of the authorization check. Always overwritten by the component, so a value set by an inbound message never survives into the route.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#ALLOWED" },
@@ -64,36 +67,40 @@
     "CamelOpenFgaObject": { "index": 4, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The object the check was made against, as resolved from the endpoint's object expression. Set for observability; it is not read as an input.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#OBJECT" },
     "CamelOpenFgaRelation": { "index": 5, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The relation that was checked. Set for observability; it is not read as an input and cannot be used to demand a weaker permission than the endpoint configured.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#RE [...]
     "CamelOpenFgaStoreId": { "index": 6, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The identifier of the OpenFGA store that was consulted, so an audit trail records which relationship graph produced the verdict.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#STORE_ID" },
-    "CamelOpenFgaWrittenTuples": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "How many relationship tuples the writeTuples operation wrote.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#WRITTEN_TUPLES" },
-    "CamelOpenFgaDeletedTuples": { "index": 8, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "How many relationship tuples the deleteTuples operation deleted.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#DELETED_TUPLES" }
+    "CamelOpenFgaContinuationToken": { "index": 7, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The continuation token the page came back with. Feed it back through the continuationToken option to read on. The two operations end differently: readTuples returns no token on its last page, so the header is absent once the [...]
+    "CamelOpenFgaWrittenTuples": { "index": 8, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "How many relationship tuples the writeTuples operation wrote.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#WRITTEN_TUPLES" },
+    "CamelOpenFgaDeletedTuples": { "index": 9, "kind": "header", "displayName": "", "group": "producer", "label": "producer", "required": false, "javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "How many relationship tuples the deleteTuples operation deleted.", "constantName": "org.apache.camel.component.openfga.OpenFgaConstants#DELETED_TUPLES" }
   },
   "properties": {
-    "operation": { "index": 0, "kind": "path", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.openfga.OpenFgaOperation", "enum": [ "check", "batchCheck", "listObjects", "listRelations", "listUsers", "writeTuples", "deleteTuples" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation to perform. The operation is taken from the endpoint only: i [...]
+    "operation": { "index": 0, "kind": "path", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.openfga.OpenFgaOperation", "enum": [ "check", "batchCheck", "listObjects", "listRelations", "listUsers", "readTuples", "readChanges", "expand", "writeTuples", "deleteTuples" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation to perform. The opera [...]
     "apiUrl": { "index": 1, "kind": "parameter", "displayName": "Api Url", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "http:\/\/localhost:8080", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The base URL of the OpenFGA HTTP API, without a trailing path. The default as [...]
     "authorizationModelId": { "index": 2, "kind": "parameter", "displayName": "Authorization Model Id", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The identifier of the authorization model revision to evaluate against. Leave it empty to u [...]
     "conditionContext": { "index": 3, "kind": "parameter", "displayName": "Condition Context", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "java.util.Map<java.lang.String, java.lang.Object>", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Context passed to the CEL expressions of any conditioned relation t [...]
     "consistency": { "index": 4, "kind": "parameter", "displayName": "Consistency", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "UNSPECIFIED", "MINIMIZE_LATENCY", "HIGHER_CONSISTENCY" ], "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The consistency the query is answered with.  [...]
     "contextualTuples": { "index": 5, "kind": "parameter", "displayName": "Contextual Tuples", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Relationship tuples supplied for the duration of one check and never stored, as semicolon-separated  [...]
-    "object": { "index": 6, "kind": "parameter", "displayName": "Object", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object being accessed, as an OpenFGA object identifier such as {code document:budget}. Evaluated as a Simple expressi [...]
-    "relation": { "index": 7, "kind": "parameter", "displayName": "Relation", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The relation to demand, such as reader or owner. Evaluated as a Simple expression against each exchange, though a lit [...]
-    "relations": { "index": 8, "kind": "parameter", "displayName": "Relations", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of relations the listRelations operation asks about, for example reader,writer,owner. Only the [...]
-    "storeId": { "index": 9, "kind": "parameter", "displayName": "Store Id", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The identifier of the OpenFGA store holding the relationship tuples and the authorization model, [...]
-    "type": { "index": 10, "kind": "parameter", "displayName": "Type", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object type to enumerate for the listObjects operation, for example document. This is a type name from the authorization [...]
-    "user": { "index": 11, "kind": "parameter", "displayName": "User", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The subject to authorize, as an OpenFGA user identifier such as {code user:anne}. Evaluated as a Simple expression against e [...]
-    "userFilters": { "index": 12, "kind": "parameter", "displayName": "User Filters", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of user filters for the listUsers operation, naming which kinds of subject to return. An [...]
-    "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...]
-    "connectTimeout": { "index": 14, "kind": "parameter", "displayName": "Connect Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for the connection to OpenFGA to be established. The component  [...]
-    "maxParallelRequests": { "index": 15, "kind": "parameter", "displayName": "Max Parallel Requests", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many of a batchCheck's checks may be in flight at once. The batch is iss [...]
-    "maxRetries": { "index": 16, "kind": "parameter", "displayName": "Max Retries", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 3, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many times the SDK retries a request that failed in a way worth retrying, such as a rate lim [...]
-    "openFgaClient": { "index": 17, "kind": "parameter", "displayName": "Open Fga Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "dev.openfga.sdk.api.client.OpenFgaClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "An existing OpenFgaClient to use. When set, every  [...]
-    "readTimeout": { "index": 18, "kind": "parameter", "displayName": "Read Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for one request to OpenFGA to complete once connected. A request that [...]
-    "apiAudience": { "index": 19, "kind": "parameter", "displayName": "Api Audience", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The audience to request the access token for in the client-credentials flow." },
-    "apiToken": { "index": 20, "kind": "parameter", "displayName": "Api Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Pre-shared token sent to OpenFGA in the Authorization header, for a server started wit [...]
-    "apiTokenIssuer": { "index": 21, "kind": "parameter", "displayName": "Api Token Issuer", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The token endpoint the client-credentials flow exchanges its credentials at." },
-    "clientId": { "index": 22, "kind": "parameter", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client identifier for the OAuth 2.0 client-credentials flow, for a server that authenticates through an OID [...]
-    "clientSecret": { "index": 23, "kind": "parameter", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client secret for the OAuth 2.0 client-credentials flow." },
-    "failOpen": { "index": 24, "kind": "parameter", "displayName": "Fail Open", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "security": "insecure:dev", "defaultValue": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Whether to let the exchange proceed when OpenFGA could not be as [...]
-    "scopes": { "index": 25, "kind": "parameter", "displayName": "Scopes", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Space-separated scopes to request in the client-credentials flow." },
-    "sslContextParameters": { "index": 26, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "TLS configuration for the connection to OpenFGA. [...]
+    "continuationToken": { "index": 6, "kind": "parameter", "displayName": "Continuation Token", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The page to read from, for readTuples and readChanges. Evaluated as a Simple expression against th [...]
+    "object": { "index": 7, "kind": "parameter", "displayName": "Object", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object being accessed, as an OpenFGA object identifier such as {code document:budget}. Evaluated as a Simple expressi [...]
+    "pageSize": { "index": 8, "kind": "parameter", "displayName": "Page Size", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many entries a readTuples or readChanges page returns. Left unset, OpenFGA's own default applies. A page is on [...]
+    "relation": { "index": 9, "kind": "parameter", "displayName": "Relation", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The relation to demand, such as reader or owner. Evaluated as a Simple expression against each exchange, though a lit [...]
+    "relations": { "index": 10, "kind": "parameter", "displayName": "Relations", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of relations the listRelations operation asks about, for example reader,writer,owner. Only th [...]
+    "startTime": { "index": 11, "kind": "parameter", "displayName": "Start Time", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The earliest change readChanges returns, as an ISO-8601 timestamp such as {code 2026-10-01T00:00:00Z}. Without it [...]
+    "storeId": { "index": 12, "kind": "parameter", "displayName": "Store Id", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The identifier of the OpenFGA store holding the relationship tuples and the authorization model [...]
+    "type": { "index": 13, "kind": "parameter", "displayName": "Type", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The object type to enumerate for the listObjects operation, for example document. This is a type name from the authorization [...]
+    "user": { "index": 14, "kind": "parameter", "displayName": "User", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The subject to authorize, as an OpenFGA user identifier such as {code user:anne}. Evaluated as a Simple expression against e [...]
+    "userFilters": { "index": 15, "kind": "parameter", "displayName": "User Filters", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Comma-separated list of user filters for the listUsers operation, naming which kinds of subject to return. An [...]
+    "lazyStartProducer": { "index": 16, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...]
+    "connectTimeout": { "index": 17, "kind": "parameter", "displayName": "Connect Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for the connection to OpenFGA to be established. The component  [...]
+    "maxParallelRequests": { "index": 18, "kind": "parameter", "displayName": "Max Parallel Requests", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 10, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many of a batchCheck's checks may be in flight at once. The batch is iss [...]
+    "maxRetries": { "index": 19, "kind": "parameter", "displayName": "Max Retries", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 3, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How many times the SDK retries a request that failed in a way worth retrying, such as a rate lim [...]
+    "openFgaClient": { "index": 20, "kind": "parameter", "displayName": "Open Fga Client", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "dev.openfga.sdk.api.client.OpenFgaClient", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "An existing OpenFgaClient to use. When set, every  [...]
+    "readTimeout": { "index": 21, "kind": "parameter", "displayName": "Read Timeout", "group": "advanced", "label": "advanced", "required": false, "type": "duration", "javaType": "long", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "10000", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "How long to wait for one request to OpenFGA to complete once connected. A request that [...]
+    "apiAudience": { "index": 22, "kind": "parameter", "displayName": "Api Audience", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The audience to request the access token for in the client-credentials flow." },
+    "apiToken": { "index": 23, "kind": "parameter", "displayName": "Api Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Pre-shared token sent to OpenFGA in the Authorization header, for a server started wit [...]
+    "apiTokenIssuer": { "index": 24, "kind": "parameter", "displayName": "Api Token Issuer", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "The token endpoint the client-credentials flow exchanges its credentials at." },
+    "clientId": { "index": 25, "kind": "parameter", "displayName": "Client Id", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client identifier for the OAuth 2.0 client-credentials flow, for a server that authenticates through an OID [...]
+    "clientSecret": { "index": 26, "kind": "parameter", "displayName": "Client Secret", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "security": "secret", "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Client secret for the OAuth 2.0 client-credentials flow." },
+    "failOpen": { "index": 27, "kind": "parameter", "displayName": "Fail Open", "group": "security", "label": "security", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "security": "insecure:dev", "defaultValue": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Whether to let the exchange proceed when OpenFGA could not be as [...]
+    "scopes": { "index": 28, "kind": "parameter", "displayName": "Scopes", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "Space-separated scopes to request in the client-credentials flow." },
+    "sslContextParameters": { "index": 29, "kind": "parameter", "displayName": "Ssl Context Parameters", "group": "security", "label": "security", "required": false, "type": "object", "javaType": "org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openfga.OpenFgaConfiguration", "configurationField": "configuration", "description": "TLS configuration for the connection to OpenFGA. [...]
   }
 }
diff --git a/components/camel-openfga/src/main/docs/openfga-component.adoc b/components/camel-openfga/src/main/docs/openfga-component.adoc
index f7c91f578588..00067a8708c6 100644
--- a/components/camel-openfga/src/main/docs/openfga-component.adoc
+++ b/components/camel-openfga/src/main/docs/openfga-component.adoc
@@ -52,8 +52,8 @@ Maven users will need to add the following dependency to their `pom.xml`.
 openfga:operation[?options]
 ------------------------------------------------------------
 
-Where `operation` is one of `check`, `batchCheck`, `listObjects`, `listRelations`, `listUsers`, `writeTuples` or
-`deleteTuples`.
+Where `operation` is one of `check`, `batchCheck`, `listObjects`, `listRelations`, `listUsers`, `readTuples`,
+`readChanges`, `expand`, `writeTuples` or `deleteTuples`.
 
 // component options: START
 include::partial$component-configure-options.adoc[]
@@ -383,9 +383,90 @@ stricter, but it would silently answer a different question than the endpoint wa
 Contextual tuples supplied by the *message* are deliberately not supported. If you need them, the tuple has to come
 from somewhere the caller cannot reach, which in practice means the endpoint.
 
+=== Reading the graph
+
+`readTuples` answers "what access exists", as opposed to `check`'s "may this subject do this". Here `user`, `relation`
+and `object` are a *filter* rather than a subject, and the body comes back as a list of maps keyed `user`, `relation`,
+`object` and `timestamp` — deliberately the keys `writeTuples` and `deleteTuples` accept, so a route can revoke what
+it just read without reshaping anything:
+
+[source,java]
+------------------------------------------------------------
+from("direct:revokeEverythingBobHas")
+        .to("openfga:readTuples?storeId={{fga.store}}&object=document:&user=user:bob")
+        .to("openfga:deleteTuples?storeId={{fga.store}}");
+------------------------------------------------------------
+
+[NOTE]
+.What OpenFGA accepts as a read filter
+====
+The filter is narrower than "every part is optional". Measured against OpenFGA 1.21.0:
+
+* no filter at all — reads the whole store, a page at a time;
+* `object=document:` *plus* a `user` — reads that user's tuples of that object type;
+* `object=document:budget` — reads that object's tuples, with or without a user or relation;
+* `user` alone, `relation` alone, or `object=document:` alone — **rejected**, because OpenFGA requires an object type
+  as soon as any filter is given and will not accept an empty object id and an empty user together.
+
+The component checks this before the call and names the option to change, rather than letting an opaque HTTP 400
+through. Note this is also why a type-only `document:` is accepted here but not as an `object` anywhere else: a read
+filter and an identifier have different rules.
+
+What "optional" does *not* mean is that a part may go missing at runtime. Only an option the endpoint never set counts
+as "do not filter on this"; an option that *is* set and evaluates to nothing — `user=${header.who}` on a message with
+no `who` header — is refused. Dropping it would make the read wider than the route asked for, and with the
+`readTuples` -> `deleteTuples` route above that turns "revoke Bob's access" into "revoke everyone's". A filter that
+silently widens when a value goes missing is the read-side form of failing open.
+====
+
+`readChanges` reads the change log, which is the building block for keeping a cache or a projection in step with the
+graph. Each entry adds an `operation` of `WRITE` or `DELETE`.
+
+Both are paged. `pageSize` bounds one request, and the token the page returns arrives on
+`CamelOpenFgaContinuationToken`; feed it back through `continuationToken` to read on.
+
+A `readChanges` poller has to carry that token from one exchange to the *next*, which an exchange property cannot do:
+every timer fire is a new exchange, so a property left on the previous one is gone and each poll would start from the
+beginning again. Use a global variable, which outlives the exchange:
+
+[source,java]
+------------------------------------------------------------
+from("timer:sync?period=30000")
+        .to("openfga:readChanges?storeId={{fga.store}}&type=document"
+            + "&continuationToken=${variable.global:fgaToken}")
+        .setVariable("global:fgaToken", header("CamelOpenFgaContinuationToken"))
+        .split(body()).to("direct:applyChange");
+------------------------------------------------------------
+
+A global variable lives in the `CamelContext`, so it does not survive a restart. A poller that must resume across one
+should keep the token wherever the deployment already persists state rather than rely on it.
+
+`startTime` bounds where a first read begins — without it a first `readChanges` on a busy store pages through the whole
+history before reaching anything current.
+
+[IMPORTANT]
+.The two read operations signal "done" differently
+====
+Measured against OpenFGA 1.21.0, not assumed:
+
+* `readTuples` returns no token on its last page, so `CamelOpenFgaContinuationToken` is **absent** once the read is
+  finished. Looping until the header is missing is the right way to drain it.
+* `readChanges` returns a token **every** time, including when nothing has happened — it hands the token you sent
+  straight back with an empty page. Looping until the header is missing would therefore never end. The signal there is
+  an **empty body**, and the token it keeps returning is the bookmark the next poll resumes from, which is why the
+  component leaves it in place instead of clearing it.
+====
+
+`expand` is the odd one out: it is the only operation that does not leave a `List` on the body, because its answer is
+a tree of usersets rather than a list. The `UsersetTree` goes on the body as the SDK returns it — flattening it is
+exactly what would destroy the information the operation exists to provide. Reach for it when a check answered
+something surprising and you need to see how it got there.
+
 == What this component does not do yet
 
-* The `expand`, `readTuples` and `readChanges` operations, and store or authorization-model management.
+* Store and authorization-model management — `createStore`, `deleteStore`, `writeAuthorizationModel` and the rest.
+  These are administrative rather than integration operations, and a component that can delete the store it
+  authorizes against is a different proposition from one that can only ask it questions.
 
 == Examples
 
diff --git a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaAuthorizer.java b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaAuthorizer.java
index ef8a779725e2..25a97ee59c55 100644
--- a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaAuthorizer.java
+++ b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaAuthorizer.java
@@ -71,6 +71,7 @@ public class OpenFgaAuthorizer {
     private final Expression relation;
     private final List<Expression[]> contextualTuples;
     private final Map<String, Object> conditionContext;
+    private final Expression continuationToken;
     private final ConsistencyPreference consistency;
     private final boolean failOpen;
     private final long awaitTimeoutMillis;
@@ -84,6 +85,7 @@ public class OpenFgaAuthorizer {
         this.relation = compile(camelContext, configuration.getRelation());
         this.contextualTuples = compileContextualTuples(camelContext, configuration.getContextualTuples());
         this.conditionContext = configuration.getConditionContext();
+        this.continuationToken = compile(camelContext, configuration.getContinuationToken());
         this.consistency = parseConsistency(configuration.getConsistency());
         this.failOpen = configuration.isFailOpen();
         this.awaitTimeoutMillis = awaitTimeout(configuration);
@@ -481,6 +483,24 @@ public class OpenFgaAuthorizer {
         return user != null || relation != null || object != null;
     }
 
+    /**
+     * Whether the {@code user} option was configured at all, as opposed to having been configured and then resolving to
+     * nothing on this exchange. The read filter needs the two kept apart: only an option that was never set means "do
+     * not filter on this", for the same reason {@link #hasConfiguredTuple()} asks the compiled expressions rather than
+     * the evaluated values.
+     */
+    boolean hasConfiguredUser() {
+        return user != null;
+    }
+
+    boolean hasConfiguredRelation() {
+        return relation != null;
+    }
+
+    boolean hasConfiguredObject() {
+        return object != null;
+    }
+
     /**
      * Evaluates the {@code user}, {@code relation} and {@code object} options without the check-path guards and without
      * touching the decision headers, for the operations that write relationship tuples. There the values are not a
@@ -499,6 +519,14 @@ public class OpenFgaAuthorizer {
         return evaluate(exchange, object);
     }
 
+    /**
+     * Evaluates the {@code continuationToken} option, so a route can page by feeding back the token the previous page
+     * left on the message.
+     */
+    String rawContinuationToken(Exchange exchange) {
+        return evaluate(exchange, continuationToken);
+    }
+
     ConsistencyPreference getConsistency() {
         return consistency;
     }
diff --git a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaConfiguration.java b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaConfiguration.java
index ac7dfe70f98b..7833533fbb23 100644
--- a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaConfiguration.java
+++ b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaConfiguration.java
@@ -103,6 +103,15 @@ public class OpenFgaConfiguration implements Cloneable {
     @UriParam(label = "advanced", defaultValue = "10")
     private int maxParallelRequests = 10;
 
+    @UriParam
+    private Integer pageSize;
+
+    @UriParam
+    private String continuationToken;
+
+    @UriParam
+    private String startTime;
+
     @UriParam(label = "advanced",
               description = "An existing OpenFgaClient to use. When set, every option describing how to reach the"
                             + " server - apiUrl, storeId, the credentials, the timeouts and sslContextParameters - is"
@@ -467,6 +476,46 @@ public class OpenFgaConfiguration implements Cloneable {
         this.maxParallelRequests = maxParallelRequests;
     }
 
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    /**
+     * How many entries a {@code readTuples} or {@code readChanges} page returns. Left unset, OpenFGA's own default
+     * applies. A page is one request: this bounds the answer, not the number of requests a route makes.
+     */
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public String getContinuationToken() {
+        return continuationToken;
+    }
+
+    /**
+     * The page to read from, for {@code readTuples} and {@code readChanges}. Evaluated as a Simple expression against
+     * the exchange, so a route can feed back the token the previous page returned -
+     * <code>${header.CamelOpenFgaContinuationToken}</code> - and page through without the token being configured
+     * statically.
+     */
+    public void setContinuationToken(String continuationToken) {
+        this.continuationToken = continuationToken;
+    }
+
+    public String getStartTime() {
+        return startTime;
+    }
+
+    /**
+     * The earliest change {@code readChanges} returns, as an ISO-8601 timestamp such as {@code 2026-10-01T00:00:00Z}.
+     * Without it a first read starts at the beginning of the store's change log, which on a busy store is a lot of
+     * history to page through before reaching anything current. Parsed when the endpoint starts, so a malformed value
+     * fails there rather than on the first exchange.
+     */
+    public void setStartTime(String startTime) {
+        this.startTime = startTime;
+    }
+
     /**
      * An already-configured {@link OpenFgaClient} to use instead of letting the endpoint build one.
      */
diff --git a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaConstants.java b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaConstants.java
index 4d2a61482462..508c713a53cd 100644
--- a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaConstants.java
+++ b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaConstants.java
@@ -76,6 +76,16 @@ public final class OpenFgaConstants {
               javaType = "String")
     public static final String STORE_ID = HEADER_PREFIX + "StoreId";
 
+    @Metadata(label = "producer",
+              description = "The continuation token the page came back with. Feed it back through the"
+                            + " continuationToken option to read on. The two operations end differently: readTuples"
+                            + " returns no token on its last page, so the header is absent once the read is done,"
+                            + " whereas readChanges always returns a token - an empty body is what says the log has"
+                            + " been read up to date, and that last token is what lets the next poll resume instead"
+                            + " of replaying the whole log.",
+              javaType = "String")
+    public static final String CONTINUATION_TOKEN = HEADER_PREFIX + "ContinuationToken";
+
     @Metadata(label = "producer", description = "How many relationship tuples the writeTuples operation wrote.",
               javaType = "Integer")
     public static final String WRITTEN_TUPLES = HEADER_PREFIX + "WrittenTuples";
diff --git a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaEndpoint.java b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaEndpoint.java
index b63841f63313..9d8238c54501 100644
--- a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaEndpoint.java
+++ b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaEndpoint.java
@@ -16,6 +16,9 @@
  */
 package org.apache.camel.component.openfga;
 
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeParseException;
+
 import javax.net.ssl.SSLContext;
 
 import dev.openfga.sdk.api.client.OpenFgaClient;
@@ -56,6 +59,7 @@ public class OpenFgaEndpoint extends DefaultEndpoint {
 
     private volatile OpenFgaAuthorizer authorizer;
     private volatile SSLContext sslContext;
+    private volatile OffsetDateTime startTime;
 
     public OpenFgaEndpoint(final String uri, final Component component, final OpenFgaConfiguration configuration) {
         super(uri, component);
@@ -76,6 +80,7 @@ public class OpenFgaEndpoint extends DefaultEndpoint {
             sslContext = createSslContext();
             client = OpenFgaClientFactory.createClient(configuration, sslContext);
         }
+        this.startTime = parseStartTime();
         validateOperationOptions();
         authorizer = new OpenFgaAuthorizer(client, configuration, getCamelContext());
     }
@@ -108,9 +113,14 @@ public class OpenFgaEndpoint extends DefaultEndpoint {
                 require(configuration.getObject(), "object", "names the object to list users of");
                 require(configuration.getRelation(), "relation", "names the relation to list users for");
             }
+            case expand -> {
+                require(configuration.getObject(), "object", "names the object whose relation is expanded");
+                require(configuration.getRelation(), "relation", "names the relation to expand");
+            }
             default -> {
                 // writeTuples and deleteTuples take their tuples from the message body, falling back to the
-                // user/relation/object triple, so there is nothing that must be configured up front
+                // user/relation/object triple; readTuples treats user, relation and object as an optional filter and
+                // readChanges needs nothing at all - so none of them has anything that must be configured up front
             }
         }
     }
@@ -122,6 +132,31 @@ public class OpenFgaEndpoint extends DefaultEndpoint {
         }
     }
 
+    /**
+     * Parses {@code startTime} when the endpoint starts, so a malformed timestamp stops the route rather than failing
+     * the first exchange that happens to reach a readChanges.
+     */
+    private OffsetDateTime parseStartTime() {
+        if (ObjectHelper.isEmpty(configuration.getStartTime())) {
+            return null;
+        }
+        try {
+            return OffsetDateTime.parse(configuration.getStartTime());
+        } catch (DateTimeParseException e) {
+            throw new IllegalArgumentException(
+                    "startTime '" + configuration.getStartTime() + "' is not an ISO-8601 timestamp, for example"
+                                               + " 2026-10-01T00:00:00Z",
+                    e);
+        }
+    }
+
+    /**
+     * The parsed {@code startTime}, or null when none was configured.
+     */
+    OffsetDateTime getStartTime() {
+        return startTime;
+    }
+
     /**
      * An endpoint without a pinned {@code authorizationModelId} evaluates against whatever model the store considers
      * latest, which moves the moment somebody writes a new one. That is a reasonable default for getting started and a
diff --git a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaOperation.java b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaOperation.java
index fd5b279b9c2d..e28e47b005d0 100644
--- a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaOperation.java
+++ b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaOperation.java
@@ -52,6 +52,22 @@ public enum OpenFgaOperation {
      */
     listUsers,
 
+    /**
+     * Read the stored relationship tuples, optionally filtered by the configured user, relation and object. Paged.
+     */
+    readTuples,
+
+    /**
+     * Read the store's change log, so a route can keep an external projection in step with the graph. Paged.
+     */
+    readChanges,
+
+    /**
+     * Expand a relation on an object into its userset tree. An introspection aid: this is what you reach for when a
+     * check answered something surprising and you need to see how it got there.
+     */
+    expand,
+
     /**
      * Grant access by writing relationship tuples.
      */
diff --git a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaProducer.java b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaProducer.java
index baa6b7ef66c6..71e0e37fd0d5 100644
--- a/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaProducer.java
+++ b/components/camel-openfga/src/main/java/org/apache/camel/component/openfga/OpenFgaProducer.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.openfga;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -26,19 +27,31 @@ import java.util.function.Consumer;
 
 import dev.openfga.sdk.api.client.model.ClientBatchCheckClientResponse;
 import dev.openfga.sdk.api.client.model.ClientCheckRequest;
+import dev.openfga.sdk.api.client.model.ClientExpandRequest;
+import dev.openfga.sdk.api.client.model.ClientExpandResponse;
 import dev.openfga.sdk.api.client.model.ClientListObjectsRequest;
 import dev.openfga.sdk.api.client.model.ClientListRelationsRequest;
 import dev.openfga.sdk.api.client.model.ClientListUsersRequest;
+import dev.openfga.sdk.api.client.model.ClientReadChangesRequest;
+import dev.openfga.sdk.api.client.model.ClientReadChangesResponse;
+import dev.openfga.sdk.api.client.model.ClientReadRequest;
+import dev.openfga.sdk.api.client.model.ClientReadResponse;
 import dev.openfga.sdk.api.client.model.ClientTupleKey;
 import dev.openfga.sdk.api.client.model.ClientTupleKeyWithoutCondition;
 import dev.openfga.sdk.api.configuration.ClientBatchCheckClientOptions;
+import dev.openfga.sdk.api.configuration.ClientExpandOptions;
 import dev.openfga.sdk.api.configuration.ClientListObjectsOptions;
 import dev.openfga.sdk.api.configuration.ClientListRelationsOptions;
 import dev.openfga.sdk.api.configuration.ClientListUsersOptions;
+import dev.openfga.sdk.api.configuration.ClientReadChangesOptions;
+import dev.openfga.sdk.api.configuration.ClientReadOptions;
 import dev.openfga.sdk.api.model.ConsistencyPreference;
 import dev.openfga.sdk.api.model.FgaObject;
+import dev.openfga.sdk.api.model.TupleChange;
+import dev.openfga.sdk.api.model.TupleKey;
 import dev.openfga.sdk.api.model.User;
 import dev.openfga.sdk.api.model.UserTypeFilter;
+import dev.openfga.sdk.api.model.UsersetTree;
 import org.apache.camel.Exchange;
 import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.health.HealthCheckHelper;
@@ -113,6 +126,9 @@ public class OpenFgaProducer extends DefaultProducer {
             case listRelations -> listRelations(exchange, authorizer);
             case listUsers -> listUsers(exchange, authorizer);
             case writeTuples -> writeTuples(exchange, authorizer);
+            case readTuples -> readTuples(exchange, authorizer);
+            case readChanges -> readChanges(exchange, authorizer);
+            case expand -> expand(exchange, authorizer);
             case deleteTuples -> deleteTuples(exchange, authorizer);
             // unreachable today; here so that adding an operation to the enum without wiring it up fails loudly
             // instead of silently letting the exchange through an endpoint that was asked to authorize it
@@ -304,6 +320,239 @@ public class OpenFgaProducer extends DefaultProducer {
         exchange.getMessage().setBody(identifiers);
     }
 
+    /**
+     * Reads the stored relationship tuples, filtered by whichever of user, relation and object the endpoint configured.
+     * <p/>
+     * Unlike every other operation these three are optional here: a part the endpoint never set means "do not filter on
+     * this", and leaving all three unset reads the whole store a page at a time. That is why the raw resolvers are used
+     * rather than the check-path ones, which treat a blank value as a missing identity and deny. A part that WAS set
+     * and resolves to nothing is a different thing entirely - see {@link #readFilterPart}.
+     */
+    private void readTuples(Exchange exchange, OpenFgaAuthorizer authorizer) throws Exception {
+        String filterUser = readFilterPart(authorizer.hasConfiguredUser(), authorizer.rawUser(exchange), "user");
+        String filterRelation
+                = readFilterPart(authorizer.hasConfiguredRelation(), authorizer.rawRelation(exchange), "relation");
+        String filterObject = readFilterPart(authorizer.hasConfiguredObject(), authorizer.rawObject(exchange), "object");
+        validateReadFilter(filterUser, filterRelation, filterObject);
+
+        ClientReadRequest request = new ClientReadRequest();
+        if (filterUser != null) {
+            request.user(filterUser);
+        }
+        if (filterRelation != null) {
+            request.relation(filterRelation);
+        }
+        if (filterObject != null) {
+            request._object(filterObject);
+        }
+
+        ClientReadOptions options = new ClientReadOptions();
+        if (getEndpoint().getConfiguration().getPageSize() != null) {
+            options.pageSize(getEndpoint().getConfiguration().getPageSize());
+        }
+        String token = authorizer.rawContinuationToken(exchange);
+        if (ObjectHelper.isNotEmpty(token)) {
+            options.continuationToken(token);
+        }
+        if (authorizer.getConsistency() != null) {
+            options.consistency(authorizer.getConsistency());
+        }
+
+        ClientReadResponse response = authorizer.await(exchange, "read the stored tuples",
+                () -> authorizer.getClient().read(request, options));
+
+        List<Map<String, Object>> tuples = new ArrayList<>();
+        if (response.getTuples() != null) {
+            // qualified because this class already has its own Tuple, the holder the write paths use; that one is
+            // referenced far more often, so it keeps the simple name
+            for (dev.openfga.sdk.api.model.Tuple tuple : response.getTuples()) {
+                TupleKey key = tuple.getKey();
+                if (key == null) {
+                    continue;
+                }
+                // the user/relation/object keys are deliberately the ones writeTuples and deleteTuples accept, so a
+                // route can feed what it read straight back into a revoke without reshaping it
+                Map<String, Object> entry = new LinkedHashMap<>();
+                entry.put("user", key.getUser());
+                entry.put("relation", key.getRelation());
+                entry.put("object", key.getObject());
+                entry.put("timestamp", tuple.getTimestamp());
+                tuples.add(entry);
+            }
+        }
+        setContinuationToken(exchange, response.getContinuationToken());
+        exchange.getMessage().setBody(tuples);
+    }
+
+    /**
+     * Reads the store's change log, so a route can keep something outside OpenFGA in step with the graph.
+     */
+    private void readChanges(Exchange exchange, OpenFgaAuthorizer authorizer) throws Exception {
+        ClientReadChangesRequest request = new ClientReadChangesRequest();
+        if (ObjectHelper.isNotEmpty(getEndpoint().getConfiguration().getType())) {
+            request.type(getEndpoint().getConfiguration().getType());
+        }
+        if (getEndpoint().getStartTime() != null) {
+            request.startTime(getEndpoint().getStartTime());
+        }
+
+        ClientReadChangesOptions options = new ClientReadChangesOptions();
+        if (getEndpoint().getConfiguration().getPageSize() != null) {
+            options.pageSize(getEndpoint().getConfiguration().getPageSize());
+        }
+        String token = authorizer.rawContinuationToken(exchange);
+        if (ObjectHelper.isNotEmpty(token)) {
+            options.continuationToken(token);
+        }
+
+        ClientReadChangesResponse response = authorizer.await(exchange, "read the change log",
+                () -> authorizer.getClient().readChanges(request, options));
+
+        List<Map<String, Object>> changes = new ArrayList<>();
+        if (response.getChanges() != null) {
+            for (TupleChange change : response.getChanges()) {
+                TupleKey key = change.getTupleKey();
+                if (key == null) {
+                    continue;
+                }
+                Map<String, Object> entry = new LinkedHashMap<>();
+                entry.put("user", key.getUser());
+                entry.put("relation", key.getRelation());
+                entry.put("object", key.getObject());
+                // the enum's name rather than the enum, so a route can compare against "WRITE" without importing
+                // an SDK type, and so the body marshals without a custom serializer
+                entry.put("operation", change.getOperation() != null ? change.getOperation().name() : null);
+                entry.put("timestamp", change.getTimestamp());
+                changes.add(entry);
+            }
+        }
+        setContinuationToken(exchange, response.getContinuationToken());
+        exchange.getMessage().setBody(changes);
+    }
+
+    /**
+     * Expands a relation on an object into its userset tree.
+     * <p/>
+     * This is the one operation that does not leave a {@code List<String>} on the body, because its answer is not a
+     * list: it is a tree of usersets explaining how a relation resolves. The {@link UsersetTree} goes on the body as it
+     * comes back from the SDK rather than being flattened, since flattening is exactly what destroys the information
+     * the operation exists to provide.
+     */
+    private void expand(Exchange exchange, OpenFgaAuthorizer authorizer) throws Exception {
+        OpenFgaAuthorizer.clearDecisionHeaders(exchange);
+        String object = authorizer.resolveObject(exchange);
+        String relation = authorizer.resolveRelation(exchange);
+        if (object == null || relation == null) {
+            exchange.getMessage().setBody(null);
+            return;
+        }
+
+        ClientExpandRequest request = new ClientExpandRequest()
+                ._object(object)
+                .relation(relation);
+        ClientExpandOptions options = new ClientExpandOptions();
+        applyModelAndConsistency(authorizer, options::authorizationModelId, options::consistency);
+
+        ClientExpandResponse response = authorizer.await(exchange, "expand " + relation + " on " + object,
+                () -> authorizer.getClient().expand(request, options));
+        exchange.getMessage().setBody(response.getTree());
+    }
+
+    /**
+     * Resolves one part of a read filter, keeping "never configured" and "configured but resolved to nothing" apart.
+     * <p/>
+     * Only an option the endpoint never set means "do not filter on this". An option that IS set and evaluates to blank
+     * - {@code user=${header.who}} on an exchange carrying no such header - is a failure to resolve, and dropping it
+     * would make the read WIDER than the route asked for: a filter meant to select one subject's tuples would instead
+     * return every tuple on the object, and the documented {@code readTuples -> deleteTuples} route would then revoke
+     * all of them. Widening a filter on a value that went missing is the read-side form of failing open, so it is
+     * refused. Same reasoning as {@link OpenFgaAuthorizer#hasConfiguredTuple()} on the write path.
+     */
+    private static String readFilterPart(boolean configured, String value, String option) {
+        if (!configured) {
+            return null;
+        }
+        String trimmed = trimmedOrNull(value);
+        if (trimmed == null) {
+            throw new IllegalArgumentException(
+                    option + " is configured for the readTuples operation but resolved to nothing on this exchange:"
+                                               + " dropping it would read more than was asked for, so it is refused rather than widened");
+        }
+        return trimmed;
+    }
+
+    private static String trimmedOrNull(String value) {
+        if (ObjectHelper.isEmpty(value)) {
+            return null;
+        }
+        String trimmed = value.trim();
+        return trimmed.isEmpty() ? null : trimmed;
+    }
+
+    /**
+     * Checks a read filter against what OpenFGA's Read API actually accepts, which is narrower than "every part is
+     * optional".
+     * <p/>
+     * Measured against OpenFGA 1.21.0: no filter at all reads the whole store, {@code object=document:} with a user or
+     * a full {@code object=document:budget} are accepted, and a filter of user alone, relation alone, or object type
+     * alone is rejected with an HTTP 400 reading <em>"the 'tuple_key' field was provided but the object type field is
+     * required and both the object id and user cannot be empty"</em>. Catching it here turns that into something that
+     * names the option to change.
+     * <p/>
+     * Note that the object is deliberately not put through {@link OpenFgaIdentifiers#validateTupleValue}: a type-only
+     * {@code document:} is a legitimate read filter and not a legitimate identifier, so the two have different rules.
+     */
+    private static void validateReadFilter(String user, String relation, String object) {
+        if (user == null && relation == null && object == null) {
+            return;
+        }
+        // only the parts that were actually given: here an unset part means "do not filter on this", which is the
+        // opposite of what it means on the write path, where reject() must still fire for a configured part that
+        // resolved to nothing
+        if (user != null) {
+            reject(OpenFgaIdentifiers.validateTupleValue(user), "user", user, false);
+        }
+        if (relation != null) {
+            reject(OpenFgaIdentifiers.validateRelation(relation), "relation", relation, false);
+        }
+        if (object == null) {
+            throw new IllegalArgumentException(
+                    "A readTuples filter must include object: OpenFGA requires an object type as soon as any filter is"
+                                               + " given. Use object=<type>: to filter on the type alone, or leave"
+                                               + " user, relation and object all unset to read the whole store");
+        }
+        int separator = object.indexOf(':');
+        if (separator <= 0) {
+            throw new IllegalArgumentException(
+                    "The object filter '" + object + "' must name a type, as in document: or document:budget");
+        }
+        if (separator == object.length() - 1 && user == null) {
+            throw new IllegalArgumentException(
+                    "A readTuples filter of object type alone is not enough for OpenFGA: give an object id"
+                                               + " (object=" + object + "<id>) or a user (user=<type>:<id>) alongside"
+                                               + " object=" + object);
+        }
+    }
+
+    /**
+     * Records the page token, and removes a token a previous exchange left behind when the server returned none -
+     * otherwise a route looping on the header would read the same final page for ever.
+     * <p/>
+     * Which of the two happens is the server's choice, not this component's, and the two read operations differ
+     * (measured against OpenFGA 1.21.0): the Read API returns an empty token on its last page, so the header really
+     * does disappear once readTuples is done; readChanges echoes the request's token back with an empty page instead,
+     * because a change log is a tailing cursor rather than a finite list - that token is the bookmark the next poll
+     * resumes from, so it is deliberately left in place and an empty body is what signals "up to date". Removing it
+     * there would break incremental sync rather than improve it.
+     */
+    private static void setContinuationToken(Exchange exchange, String token) {
+        if (ObjectHelper.isNotEmpty(token)) {
+            exchange.getMessage().setHeader(OpenFgaConstants.CONTINUATION_TOKEN, token);
+        } else {
+            exchange.getMessage().removeHeader(OpenFgaConstants.CONTINUATION_TOKEN);
+        }
+    }
+
     /**
      * Writes relationship tuples, granting access.
      */
diff --git a/components/camel-openfga/src/test/java/org/apache/camel/component/openfga/OpenFgaIT.java b/components/camel-openfga/src/test/java/org/apache/camel/component/openfga/OpenFgaIT.java
index 6db1883771f7..9d62dd013e17 100644
--- a/components/camel-openfga/src/test/java/org/apache/camel/component/openfga/OpenFgaIT.java
+++ b/components/camel-openfga/src/test/java/org/apache/camel/component/openfga/OpenFgaIT.java
@@ -120,6 +120,15 @@ class OpenFgaIT extends CamelTestSupport {
                 from("direct:guarded")
                         .policy(policy)
                         .to("mock:allowed");
+
+                // the readChanges poller exactly as the component docs describe it: a global variable carries the
+                // token from one exchange to the next, which an exchange property cannot do
+                from("direct:syncChanges")
+                        .to(openfga("readChanges", "pageSize=1&continuationToken=${variable.global:fgaToken}"))
+                        .setVariable("global:fgaToken", header(OpenFgaConstants.CONTINUATION_TOKEN));
+
+                from("direct:resetSync")
+                        .removeVariable("global:fgaToken");
             }
         };
     }
@@ -237,6 +246,96 @@ class OpenFgaIT extends CamelTestSupport {
                 .isEqualTo(false);
     }
 
+    @Test
+    void readsTheStoredTuplesInAShapeDeleteTuplesAccepts() {
+        Exchange read = template.request(openfga("readTuples", "object=document:&user=user:bob"), e -> {
+        });
+
+        assertThat(read.getException()).isNull();
+        assertThat(read.getMessage().getBody(List.class)).isNotEmpty();
+        // bob's only stored tuple is reader on the roadmap
+        assertThat(read.getMessage().getBody(List.class)).anySatisfy(entry -> {
+            Map<?, ?> tuple = (Map<?, ?>) entry;
+            assertThat(tuple.get("user")).isEqualTo("user:bob");
+            assertThat(tuple.get("relation")).isEqualTo("reader");
+            assertThat(tuple.get("object")).isEqualTo("document:roadmap");
+        });
+    }
+
+    @Test
+    void readsTheChangeLogAndPagesWithTheContinuationToken() {
+        Exchange firstPage = template.request(openfga("readChanges", "pageSize=1"), e -> {
+        });
+
+        assertThat(firstPage.getException()).isNull();
+        assertThat(firstPage.getMessage().getBody(List.class)).hasSize(1);
+        assertThat(((Map<?, ?>) firstPage.getMessage().getBody(List.class).get(0)).get("operation"))
+                .isEqualTo("WRITE");
+
+        String token = firstPage.getMessage().getHeader(OpenFgaConstants.CONTINUATION_TOKEN, String.class);
+        assertThat(token).isNotBlank();
+
+        Exchange secondPage = template.request(
+                openfga("readChanges", "pageSize=1&continuationToken=${header.resume}"),
+                e -> e.getMessage().setHeader("resume", token));
+
+        assertThat(secondPage.getException()).isNull();
+        assertThat(secondPage.getMessage().getBody(List.class)).hasSize(1);
+        // a different change than the first page, which is what paging is for
+        assertThat(secondPage.getMessage().getBody(List.class).get(0))
+                .isNotEqualTo(firstPage.getMessage().getBody(List.class).get(0));
+    }
+
+    @Test
+    void aGlobalVariableCarriesThePagingTokenBetweenExchanges() {
+        template.sendBody("direct:resetSync", "");
+
+        Exchange firstPoll = template.request("direct:syncChanges", e -> {
+        });
+        Exchange secondPoll = template.request("direct:syncChanges", e -> {
+        });
+
+        assertThat(firstPoll.getException()).isNull();
+        assertThat(secondPoll.getException()).isNull();
+        assertThat(firstPoll.getMessage().getBody(List.class)).hasSize(1);
+        assertThat(secondPoll.getMessage().getBody(List.class)).hasSize(1);
+        // with an exchange property the second poll would have started over and returned the same change again
+        assertThat(secondPoll.getMessage().getBody(List.class).get(0))
+                .isNotEqualTo(firstPoll.getMessage().getBody(List.class).get(0));
+    }
+
+    @Test
+    void readChangesHandsTheTokenBackWhenTheLogIsExhausted() {
+        String[] token = { null };
+        List<?> changes;
+        int guard = 0;
+        do {
+            Exchange out = template.request(
+                    openfga("readChanges", "pageSize=50&continuationToken=${header.resume}"),
+                    e -> e.getMessage().setHeader("resume", token[0]));
+            assertThat(out.getException()).isNull();
+            changes = out.getMessage().getBody(List.class);
+            token[0] = out.getMessage().getHeader(OpenFgaConstants.CONTINUATION_TOKEN, String.class);
+            assertThat(token[0]).as("readChanges returns a token on every page, the empty one included").isNotBlank();
+        } while (!changes.isEmpty() && ++guard < 20);
+
+        // the asymmetry the docs spell out: readChanges never drops the token, so an EMPTY BODY - not an absent
+        // header - says the log has been read up to date. A route looping until the header disappeared would not end
+        assertThat(changes).isEmpty();
+        assertThat(token[0]).isNotBlank();
+    }
+
+    @Test
+    void expandShowsHowARelationResolves() {
+        Exchange out = template.request(openfga("expand", "object=document:budget&relation=reader"), e -> {
+        });
+
+        assertThat(out.getException()).isNull();
+        // anne reads the budget through owner, so the tree must mention the relation rather than just listing her
+        assertThat(out.getMessage().getBody()).isNotNull();
+        assertThat(out.getMessage().getBody().toString()).contains("document:budget#reader");
+    }
+
     @Test
     void listsTheObjectsASubjectCanRead() {
         Exchange out = template.request(
diff --git a/components/camel-openfga/src/test/java/org/apache/camel/component/openfga/OpenFgaReadOperationsTest.java b/components/camel-openfga/src/test/java/org/apache/camel/component/openfga/OpenFgaReadOperationsTest.java
new file mode 100644
index 000000000000..14c58e11fe11
--- /dev/null
+++ b/components/camel-openfga/src/test/java/org/apache/camel/component/openfga/OpenFgaReadOperationsTest.java
@@ -0,0 +1,305 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.openfga;
+
+import java.time.OffsetDateTime;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import dev.openfga.sdk.api.client.OpenFgaClient;
+import dev.openfga.sdk.api.client.model.ClientExpandRequest;
+import dev.openfga.sdk.api.client.model.ClientExpandResponse;
+import dev.openfga.sdk.api.client.model.ClientReadChangesRequest;
+import dev.openfga.sdk.api.client.model.ClientReadChangesResponse;
+import dev.openfga.sdk.api.client.model.ClientReadRequest;
+import dev.openfga.sdk.api.client.model.ClientReadResponse;
+import dev.openfga.sdk.api.client.model.ClientTupleKeyWithoutCondition;
+import dev.openfga.sdk.api.client.model.ClientWriteResponse;
+import dev.openfga.sdk.api.configuration.ClientReadChangesOptions;
+import dev.openfga.sdk.api.configuration.ClientReadOptions;
+import dev.openfga.sdk.api.model.Node;
+import dev.openfga.sdk.api.model.Tuple;
+import dev.openfga.sdk.api.model.TupleChange;
+import dev.openfga.sdk.api.model.TupleKey;
+import dev.openfga.sdk.api.model.TupleOperation;
+import dev.openfga.sdk.api.model.UsersetTree;
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.Exchange;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class OpenFgaReadOperationsTest extends CamelTestSupport {
+
+    private static final String STORE = "01HQMVAJXYZ0000000000000";
+    private static final String BASE = "?openFgaClient=#fgaClient&storeId=" + STORE;
+
+    @BindToRegistry("fgaClient")
+    private final OpenFgaClient client = mock(OpenFgaClient.class);
+
+    private static Tuple storedTuple(String user, String relation, String object) {
+        return new Tuple()
+                .key(new TupleKey().user(user).relation(relation)._object(object))
+                .timestamp(OffsetDateTime.parse("2026-10-01T10:00:00Z"));
+    }
+
+    private void givenStoredTuples(String token, Tuple... tuples) throws Exception {
+        ClientReadResponse response = mock(ClientReadResponse.class);
+        when(response.getTuples()).thenReturn(List.of(tuples));
+        when(response.getContinuationToken()).thenReturn(token);
+        when(client.read(any(ClientReadRequest.class), any())).thenReturn(CompletableFuture.completedFuture(response));
+    }
+
+    @Test
+    void readTuplesReturnsTheShapeTheWriteOperationsAccept() throws Exception {
+        givenStoredTuples(null, storedTuple("user:anne", "owner", "document:budget"));
+
+        Exchange out = template.request("openfga:readTuples" + BASE, e -> {
+        });
+
+        assertThat(out.getException()).isNull();
+        assertThat(out.getMessage().getBody(List.class)).singleElement()
+                .satisfies(entry -> {
+                    Map<?, ?> tuple = (Map<?, ?>) entry;
+                    assertThat(tuple.get("user")).isEqualTo("user:anne");
+                    assertThat(tuple.get("relation")).isEqualTo("owner");
+                    assertThat(tuple.get("object")).isEqualTo("document:budget");
+                    assertThat(tuple.get("timestamp")).isEqualTo(OffsetDateTime.parse("2026-10-01T10:00:00Z"));
+                });
+    }
+
+    @Test
+    void whatReadTuplesReturnsCanBeRevokedWithoutReshaping() throws Exception {
+        // the point of using user/relation/object as the keys: a read feeds a revoke directly
+        givenStoredTuples(null, storedTuple("user:bob", "reader", "document:roadmap"));
+        when(client.deleteTuples(anyList()))
+                .thenReturn(CompletableFuture.completedFuture(mock(ClientWriteResponse.class)));
+
+        Exchange read = template.request("openfga:readTuples" + BASE, e -> {
+        });
+        Exchange revoked = template.request("openfga:deleteTuples" + BASE,
+                e -> e.getMessage().setBody(read.getMessage().getBody()));
+
+        assertThat(revoked.getException()).isNull();
+        assertThat(revoked.getMessage().getHeader(OpenFgaConstants.DELETED_TUPLES)).isEqualTo(1);
+        ArgumentCaptor<List<ClientTupleKeyWithoutCondition>> captor = ArgumentCaptor.captor();
+        verify(client).deleteTuples(captor.capture());
+        assertThat(captor.getValue()).singleElement()
+                .satisfies(tuple -> {
+                    assertThat(tuple.getUser()).isEqualTo("user:bob");
+                    assertThat(tuple.getObject()).isEqualTo("document:roadmap");
+                });
+    }
+
+    @Test
+    void readTuplesAppliesTheConfiguredFilterAndPaging() throws Exception {
+        givenStoredTuples("tok-2", storedTuple("user:anne", "owner", "document:budget"));
+
+        Exchange out = template.request(
+                "openfga:readTuples" + BASE + "&user=user:anne&relation=owner&object=document:&pageSize=25"
+                                        + "&continuationToken=${header.resume}",
+                e -> e.getMessage().setHeader("resume", "tok-1"));
+
+        ArgumentCaptor<ClientReadRequest> request = ArgumentCaptor.forClass(ClientReadRequest.class);
+        ArgumentCaptor<ClientReadOptions> options = ArgumentCaptor.forClass(ClientReadOptions.class);
+        verify(client).read(request.capture(), options.capture());
+        assertThat(request.getValue().getUser()).isEqualTo("user:anne");
+        assertThat(request.getValue().getRelation()).isEqualTo("owner");
+        assertThat(request.getValue().getObject()).isEqualTo("document:");
+        assertThat(options.getValue().getPageSize()).isEqualTo(25);
+        assertThat(options.getValue().getContinuationToken()).isEqualTo("tok-1");
+        assertThat(out.getMessage().getHeader(OpenFgaConstants.CONTINUATION_TOKEN)).isEqualTo("tok-2");
+    }
+
+    @Test
+    void readTuplesRemovesAStaleTokenOnTheLastPage() throws Exception {
+        givenStoredTuples(null, storedTuple("user:anne", "owner", "document:budget"));
+
+        // a route looping on the header would otherwise read the final page for ever
+        Exchange out = template.request("openfga:readTuples" + BASE,
+                e -> e.getMessage().setHeader(OpenFgaConstants.CONTINUATION_TOKEN, "tok-from-the-previous-page"));
+
+        assertThat(out.getMessage().getHeader(OpenFgaConstants.CONTINUATION_TOKEN)).isNull();
+    }
+
+    @Test
+    void readTuplesRefusesAFilterOpenFgaWouldReject() {
+        // measured against OpenFGA 1.21.0: a user-only filter comes back as HTTP 400 because the Read API wants an
+        // object type as soon as any filter is given. Catching it here names the option to change
+        Exchange userOnly = template.request("openfga:readTuples" + BASE + "&user=user:bob", e -> {
+        });
+        assertThat(userOnly.getException()).isInstanceOf(IllegalArgumentException.class);
+        assertThat(userOnly.getException()).hasMessageContaining("must include object");
+
+        Exchange typeOnly = template.request("openfga:readTuples" + BASE + "&object=document:", e -> {
+        });
+        assertThat(typeOnly.getException()).isInstanceOf(IllegalArgumentException.class);
+        assertThat(typeOnly.getException()).hasMessageContaining("object type alone is not enough");
+    }
+
+    @Test
+    void readTuplesAcceptsATypeOnlyObjectAlongsideAUser() throws Exception {
+        givenStoredTuples(null, storedTuple("user:bob", "reader", "document:roadmap"));
+
+        Exchange out = template.request("openfga:readTuples" + BASE + "&object=document:&user=user:bob", e -> {
+        });
+
+        // document: is a legitimate read filter though it is not a legitimate identifier anywhere else
+        assertThat(out.getException()).isNull();
+        assertThat(out.getMessage().getBody(List.class)).hasSize(1);
+    }
+
+    @Test
+    void readTuplesRefusesAFilterThatCouldNotBeATupleValue() throws Exception {
+        Exchange out = template.request("openfga:readTuples" + BASE + "&object=not-an-identifier", e -> {
+        });
+
+        assertThat(out.getException()).isInstanceOf(IllegalArgumentException.class);
+        assertThat(out.getException()).hasMessageContaining("must name a type");
+    }
+
+    @Test
+    void readTuplesRefusesAFilterPartThatWentMissing() throws Exception {
+        givenStoredTuples(null, storedTuple("user:bob", "reader", "document:budget"));
+
+        // object=document:budget on its own is a legal filter, so dropping an unresolved user would quietly read
+        // every tuple on that document - and the documented readTuples -> deleteTuples route would revoke them all
+        Exchange out = template.request("openfga:readTuples" + BASE + "&object=document:budget&user=${header.who}",
+                e -> {
+                });
+
+        assertThat(out.getException()).isInstanceOf(IllegalArgumentException.class);
+        assertThat(out.getException()).hasMessageContaining("user is configured for the readTuples operation");
+        verify(client, never()).read(any(ClientReadRequest.class), any());
+    }
+
+    @Test
+    void readTuplesWithNoFilterConfiguredStillReadsEverything() throws Exception {
+        givenStoredTuples(null, storedTuple("user:bob", "reader", "document:budget"));
+
+        Exchange out = template.request("openfga:readTuples" + BASE, e -> {
+        });
+
+        // an option that was never set is the only thing that means "do not filter on this"
+        assertThat(out.getException()).isNull();
+        ArgumentCaptor<ClientReadRequest> request = ArgumentCaptor.forClass(ClientReadRequest.class);
+        verify(client).read(request.capture(), any());
+        assertThat(request.getValue().getUser()).isNull();
+        assertThat(request.getValue().getRelation()).isNull();
+        assertThat(request.getValue().getObject()).isNull();
+    }
+
+    @Test
+    void readChangesReportsTheOperationAsItsName() throws Exception {
+        ClientReadChangesResponse response = mock(ClientReadChangesResponse.class);
+        when(response.getChanges()).thenReturn(List.of(
+                new TupleChange()
+                        .tupleKey(new TupleKey().user("user:anne").relation("owner")._object("document:budget"))
+                        .operation(TupleOperation.WRITE)
+                        .timestamp(OffsetDateTime.parse("2026-10-01T10:00:00Z")),
+                new TupleChange()
+                        .tupleKey(new TupleKey().user("user:bob").relation("reader")._object("document:roadmap"))
+                        .operation(TupleOperation.DELETE)
+                        .timestamp(OffsetDateTime.parse("2026-10-01T11:00:00Z"))));
+        when(response.getContinuationToken()).thenReturn("tok-9");
+        when(client.readChanges(any(ClientReadChangesRequest.class), any()))
+                .thenReturn(CompletableFuture.completedFuture(response));
+
+        Exchange out = template.request(
+                "openfga:readChanges" + BASE + "&type=document&pageSize=50&startTime=2026-10-01T00:00:00Z", e -> {
+                });
+
+        assertThat(out.getException()).isNull();
+        assertThat(out.getMessage().getBody(List.class)).hasSize(2);
+        assertThat(((Map<?, ?>) out.getMessage().getBody(List.class).get(0)).get("operation")).isEqualTo("WRITE");
+        assertThat(((Map<?, ?>) out.getMessage().getBody(List.class).get(1)).get("operation")).isEqualTo("DELETE");
+        assertThat(out.getMessage().getHeader(OpenFgaConstants.CONTINUATION_TOKEN)).isEqualTo("tok-9");
+
+        ArgumentCaptor<ClientReadChangesRequest> request = ArgumentCaptor.forClass(ClientReadChangesRequest.class);
+        ArgumentCaptor<ClientReadChangesOptions> options = ArgumentCaptor.forClass(ClientReadChangesOptions.class);
+        verify(client).readChanges(request.capture(), options.capture());
+        assertThat(request.getValue().getType()).isEqualTo("document");
+        assertThat(request.getValue().getStartTime()).isEqualTo(OffsetDateTime.parse("2026-10-01T00:00:00Z"));
+        assertThat(options.getValue().getPageSize()).isEqualTo(50);
+    }
+
+    @Test
+    void readChangesKeepsTheTokenWhenNothingHasChanged() throws Exception {
+        ClientReadChangesResponse response = mock(ClientReadChangesResponse.class);
+        when(response.getChanges()).thenReturn(List.of());
+        when(response.getContinuationToken()).thenReturn("tok-9");
+        when(client.readChanges(any(ClientReadChangesRequest.class), any()))
+                .thenReturn(CompletableFuture.completedFuture(response));
+
+        Exchange out = template.request("openfga:readChanges" + BASE + "&continuationToken=tok-9", e -> {
+        });
+
+        // measured against OpenFGA 1.21.0: readChanges hands the token straight back with an empty page rather than
+        // dropping it, so an empty body - not an absent header - is what says the log has been read up to date. A
+        // route that looped until the header disappeared would never end, which is why the docs split the two
+        assertThat(out.getException()).isNull();
+        assertThat(out.getMessage().getBody(List.class)).isEmpty();
+        assertThat(out.getMessage().getHeader(OpenFgaConstants.CONTINUATION_TOKEN)).isEqualTo("tok-9");
+    }
+
+    @Test
+    void refusesAStartTimeThatIsNotATimestampWhenTheEndpointStarts() {
+        assertThatThrownBy(() -> {
+            OpenFgaEndpoint endpoint
+                    = context.getEndpoint("openfga:readChanges" + BASE + "&startTime=yesterday", OpenFgaEndpoint.class);
+            endpoint.start();
+        }).hasStackTraceContaining("startTime 'yesterday' is not an ISO-8601 timestamp");
+    }
+
+    @Test
+    void expandPutsTheUsersetTreeOnTheBody() throws Exception {
+        UsersetTree tree = new UsersetTree().root(new Node().name("document:budget#reader"));
+        ClientExpandResponse response = mock(ClientExpandResponse.class);
+        when(response.getTree()).thenReturn(tree);
+        when(client.expand(any(ClientExpandRequest.class), any()))
+                .thenReturn(CompletableFuture.completedFuture(response));
+
+        Exchange out = template.request(
+                "openfga:expand" + BASE + "&object=document:budget&relation=reader", e -> {
+                });
+
+        assertThat(out.getException()).isNull();
+        // the one operation that does not leave a List<String>: flattening a tree destroys what it exists to show
+        assertThat(out.getMessage().getBody()).isSameAs(tree);
+        assertThat(out.getMessage().getBody(UsersetTree.class).getRoot().getName())
+                .isEqualTo("document:budget#reader");
+    }
+
+    @Test
+    void expandRequiresAnObjectAndARelation() {
+        assertThatThrownBy(() -> {
+            OpenFgaEndpoint endpoint
+                    = context.getEndpoint("openfga:expand" + BASE + "&object=document:budget", OpenFgaEndpoint.class);
+            endpoint.start();
+        }).hasStackTraceContaining("relation is required for the expand operation");
+    }
+}
diff --git a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/OpenfgaComponentBuilderFactory.java b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/OpenfgaComponentBuilderFactory.java
index c30b97b4b886..8c640b2008ed 100644
--- a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/OpenfgaComponentBuilderFactory.java
+++ b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/OpenfgaComponentBuilderFactory.java
@@ -192,6 +192,25 @@ public interface OpenfgaComponentBuilderFactory {
             return this;
         }
     
+        /**
+         * The page to read from, for readTuples and readChanges. Evaluated as a
+         * Simple expression against the exchange, so a route can feed back the
+         * token the previous page returned -
+         * ${header.CamelOpenFgaContinuationToken} - and page through without
+         * the token being configured statically.
+         * 
+         * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
+         * 
+         * Group: producer
+         * 
+         * @param continuationToken the value to set
+         * @return the dsl builder
+         */
+        default OpenfgaComponentBuilder continuationToken(java.lang.String continuationToken) {
+            doSetProperty("continuationToken", continuationToken);
+            return this;
+        }
+    
         
         /**
          * Whether the producer should be started lazy (on the first message).
@@ -237,6 +256,23 @@ public interface OpenfgaComponentBuilderFactory {
             return this;
         }
     
+        /**
+         * How many entries a readTuples or readChanges page returns. Left
+         * unset, OpenFGA's own default applies. A page is one request: this
+         * bounds the answer, not the number of requests a route makes.
+         * 
+         * The option is a: &lt;code&gt;java.lang.Integer&lt;/code&gt; type.
+         * 
+         * Group: producer
+         * 
+         * @param pageSize the value to set
+         * @return the dsl builder
+         */
+        default OpenfgaComponentBuilder pageSize(java.lang.Integer pageSize) {
+            doSetProperty("pageSize", pageSize);
+            return this;
+        }
+    
         /**
          * The relation to demand, such as reader or owner. Evaluated as a
          * Simple expression against each exchange, though a literal is what you
@@ -274,6 +310,26 @@ public interface OpenfgaComponentBuilderFactory {
             return this;
         }
     
+        /**
+         * The earliest change readChanges returns, as an ISO-8601 timestamp
+         * such as {code 2026-10-01T00:00:00Z}. Without it a first read starts
+         * at the beginning of the store's change log, which on a busy store is
+         * a lot of history to page through before reaching anything current.
+         * Parsed when the endpoint starts, so a malformed value fails there
+         * rather than on the first exchange.
+         * 
+         * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
+         * 
+         * Group: producer
+         * 
+         * @param startTime the value to set
+         * @return the dsl builder
+         */
+        default OpenfgaComponentBuilder startTime(java.lang.String startTime) {
+            doSetProperty("startTime", startTime);
+            return this;
+        }
+    
         /**
          * The identifier of the OpenFGA store holding the relationship tuples
          * and the authorization model, as returned by {code fga store create}.
@@ -710,10 +766,13 @@ public interface OpenfgaComponentBuilderFactory {
             case "configuration": ((OpenFgaComponent) component).setConfiguration((org.apache.camel.component.openfga.OpenFgaConfiguration) value); return true;
             case "consistency": getOrCreateConfiguration((OpenFgaComponent) component).setConsistency((java.lang.String) value); return true;
             case "contextualTuples": getOrCreateConfiguration((OpenFgaComponent) component).setContextualTuples((java.lang.String) value); return true;
+            case "continuationToken": getOrCreateConfiguration((OpenFgaComponent) component).setContinuationToken((java.lang.String) value); return true;
             case "lazyStartProducer": ((OpenFgaComponent) component).setLazyStartProducer((boolean) value); return true;
             case "object": getOrCreateConfiguration((OpenFgaComponent) component).setObject((java.lang.String) value); return true;
+            case "pageSize": getOrCreateConfiguration((OpenFgaComponent) component).setPageSize((java.lang.Integer) value); return true;
             case "relation": getOrCreateConfiguration((OpenFgaComponent) component).setRelation((java.lang.String) value); return true;
             case "relations": getOrCreateConfiguration((OpenFgaComponent) component).setRelations((java.lang.String) value); return true;
+            case "startTime": getOrCreateConfiguration((OpenFgaComponent) component).setStartTime((java.lang.String) value); return true;
             case "storeId": getOrCreateConfiguration((OpenFgaComponent) component).setStoreId((java.lang.String) value); return true;
             case "type": getOrCreateConfiguration((OpenFgaComponent) component).setType((java.lang.String) value); return true;
             case "user": getOrCreateConfiguration((OpenFgaComponent) component).setUser((java.lang.String) value); return true;
diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
index 453691724f51..428401406594 100644
--- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
+++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
@@ -12874,8 +12874,9 @@ public class StaticEndpointBuilders {
      * it is deliberately not overridable by a message header, so that an
      * inbound message cannot turn a check into a tuple write, nor a check for
      * one relation into a check for a weaker one.
-     * There are 7 enums and the value can be one of: check, batchCheck,
-     * listObjects, listRelations, listUsers, writeTuples, deleteTuples
+     * There are 10 enums and the value can be one of: check, batchCheck,
+     * listObjects, listRelations, listUsers, readTuples, readChanges, expand,
+     * writeTuples, deleteTuples
      * 
      * @param path operation
      * @return the dsl builder
@@ -12899,8 +12900,9 @@ public class StaticEndpointBuilders {
      * it is deliberately not overridable by a message header, so that an
      * inbound message cannot turn a check into a tuple write, nor a check for
      * one relation into a check for a weaker one.
-     * There are 7 enums and the value can be one of: check, batchCheck,
-     * listObjects, listRelations, listUsers, writeTuples, deleteTuples
+     * There are 10 enums and the value can be one of: check, batchCheck,
+     * listObjects, listRelations, listUsers, readTuples, readChanges, expand,
+     * writeTuples, deleteTuples
      * 
      * @param componentName to use a custom component name for the endpoint
      * instead of the default name
diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenFgaEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenFgaEndpointBuilderFactory.java
index defe63105cac..580bee6c6a62 100644
--- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenFgaEndpointBuilderFactory.java
+++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenFgaEndpointBuilderFactory.java
@@ -190,6 +190,24 @@ public interface OpenFgaEndpointBuilderFactory {
             doSetProperty("contextualTuples", contextualTuples);
             return this;
         }
+        /**
+         * The page to read from, for readTuples and readChanges. Evaluated as a
+         * Simple expression against the exchange, so a route can feed back the
+         * token the previous page returned -
+         * ${header.CamelOpenFgaContinuationToken} - and page through without
+         * the token being configured statically.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: producer
+         * 
+         * @param continuationToken the value to set
+         * @return the dsl builder
+         */
+        default OpenFgaEndpointBuilder continuationToken(String continuationToken) {
+            doSetProperty("continuationToken", continuationToken);
+            return this;
+        }
         /**
          * The object being accessed, as an OpenFGA object identifier such as
          * {code document:budget}. Evaluated as a Simple expression against each
@@ -209,6 +227,39 @@ public interface OpenFgaEndpointBuilderFactory {
             doSetProperty("object", object);
             return this;
         }
+        /**
+         * How many entries a readTuples or readChanges page returns. Left
+         * unset, OpenFGA's own default applies. A page is one request: this
+         * bounds the answer, not the number of requests a route makes.
+         * 
+         * The option is a: <code>java.lang.Integer</code> type.
+         * 
+         * Group: producer
+         * 
+         * @param pageSize the value to set
+         * @return the dsl builder
+         */
+        default OpenFgaEndpointBuilder pageSize(Integer pageSize) {
+            doSetProperty("pageSize", pageSize);
+            return this;
+        }
+        /**
+         * How many entries a readTuples or readChanges page returns. Left
+         * unset, OpenFGA's own default applies. A page is one request: this
+         * bounds the answer, not the number of requests a route makes.
+         * 
+         * The option will be converted to a <code>java.lang.Integer</code>
+         * type.
+         * 
+         * Group: producer
+         * 
+         * @param pageSize the value to set
+         * @return the dsl builder
+         */
+        default OpenFgaEndpointBuilder pageSize(String pageSize) {
+            doSetProperty("pageSize", pageSize);
+            return this;
+        }
         /**
          * The relation to demand, such as reader or owner. Evaluated as a
          * Simple expression against each exchange, though a literal is what you
@@ -244,6 +295,25 @@ public interface OpenFgaEndpointBuilderFactory {
             doSetProperty("relations", relations);
             return this;
         }
+        /**
+         * The earliest change readChanges returns, as an ISO-8601 timestamp
+         * such as {code 2026-10-01T00:00:00Z}. Without it a first read starts
+         * at the beginning of the store's change log, which on a busy store is
+         * a lot of history to page through before reaching anything current.
+         * Parsed when the endpoint starts, so a malformed value fails there
+         * rather than on the first exchange.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: producer
+         * 
+         * @param startTime the value to set
+         * @return the dsl builder
+         */
+        default OpenFgaEndpointBuilder startTime(String startTime) {
+            doSetProperty("startTime", startTime);
+            return this;
+        }
         /**
          * The identifier of the OpenFGA store holding the relationship tuples
          * and the authorization model, as returned by {code fga store create}.
@@ -782,8 +852,9 @@ public interface OpenFgaEndpointBuilderFactory {
          * only: it is deliberately not overridable by a message header, so that
          * an inbound message cannot turn a check into a tuple write, nor a
          * check for one relation into a check for a weaker one.
-         * There are 7 enums and the value can be one of: check, batchCheck,
-         * listObjects, listRelations, listUsers, writeTuples, deleteTuples
+         * There are 10 enums and the value can be one of: check, batchCheck,
+         * listObjects, listRelations, listUsers, readTuples, readChanges,
+         * expand, writeTuples, deleteTuples
          * 
          * @param path operation
          * @return the dsl builder
@@ -807,8 +878,9 @@ public interface OpenFgaEndpointBuilderFactory {
          * only: it is deliberately not overridable by a message header, so that
          * an inbound message cannot turn a check into a tuple write, nor a
          * check for one relation into a check for a weaker one.
-         * There are 7 enums and the value can be one of: check, batchCheck,
-         * listObjects, listRelations, listUsers, writeTuples, deleteTuples
+         * There are 10 enums and the value can be one of: check, batchCheck,
+         * listObjects, listRelations, listUsers, readTuples, readChanges,
+         * expand, writeTuples, deleteTuples
          * 
          * @param componentName to use a custom component name for the endpoint
          * instead of the default name
@@ -933,6 +1005,24 @@ public interface OpenFgaEndpointBuilderFactory {
         public String openFgaStoreId() {
             return "CamelOpenFgaStoreId";
         }
+        /**
+         * The continuation token the page came back with. Feed it back through
+         * the continuationToken option to read on. The two operations end
+         * differently: readTuples returns no token on its last page, so the
+         * header is absent once the read is done, whereas readChanges always
+         * returns a token - an empty body is what says the log has been read up
+         * to date, and that last token is what lets the next poll resume
+         * instead of replaying the whole log.
+         * 
+         * The option is a: {@code String} type.
+         * 
+         * Group: producer
+         * 
+         * @return the name of the header {@code OpenFgaContinuationToken}.
+         */
+        public String openFgaContinuationToken() {
+            return "CamelOpenFgaContinuationToken";
+        }
         /**
          * How many relationship tuples the writeTuples operation wrote.
          *