Konnektr Logo
Reference

Configuration

Complete reference for all configuration options in Konnektr Graph.

Configuration Reference

Konnektr Graph consists of two services — the API Service (REST API) and the Events Service (event streaming) — plus the Core SDK (AgeDigitalTwinsClient). Each reads configuration from appsettings.json, environment variables, or the .NET Aspire configuration system.

All configuration keys use the standard .NET configuration hierarchy. Environment variables use __ (double underscore) as a separator. For example, Parameters:TrackLastUpdatedBy becomes Parameters__TrackLastUpdatedBy.


API Service

The API Service (AgeDigitalTwins.ApiService) exposes the ADT-compatible REST API.

Connection Strings

KeyRequiredDefaultDescription
ConnectionStrings:agedbIf no Parameters:AgeConnectionString—PostgreSQL connection string
Parameters:AgeConnectionStringIf no ConnectionStrings:agedb—Fallback connection string
Parameters:UseCnpgAgeNotrueUse true for CNPG-flavor AGE images, false for Apache AGE images
Parameters:AgeGraphNameNodigitaltwinsName of the Apache AGE graph

The connection string must include the database host, port, credentials, and database name. The search path is automatically set to ag_catalog, "$user", public.

Npgsql Connection Pooling

KeyDefaultDescription
Parameters:MaxPoolSize100Maximum connections in the pool
Parameters:MinPoolSize0Minimum connections maintained in the pool
Parameters:ConnectionTimeout15Connection open timeout in seconds
Parameters:CommandTimeout30Command execution timeout in seconds
Parameters:ConnectionIdleLifetime60Max idle time before a connection is closed (seconds)
Parameters:ConnectionLifetime300Max connection lifetime before recycling (seconds)

Core SDK Options

These configure the AgeDigitalTwinsClient instance used internally.

KeyDefaultDescription
Parameters:ModelCacheExpirationSeconds10How long DTDL model definitions are cached in memory
Parameters:DefaultBatchSize50Default batch size for import jobs
Parameters:DefaultCheckpointInterval50Checkpoint interval for import jobs
Parameters:TrackLastUpdatedByfalseWhen true, stores the user ID at both the twin-level ($metadata.$lastUpdatedBy) and per-property ($metadata.<property>.lastUpdatedBy) metadata. See Security for details.

Authentication

Authentication is disabled by default and must be explicitly enabled.

KeyRequiredDefaultDescription
Authentication:EnabledYesfalseSet to true to enable JWT Bearer authentication
Authentication:AuthorityIf enabled—OAuth authority URL (e.g., https://your-tenant.auth0.com/)
Authentication:AudienceIf enabled—Expected JWT audience (e.g., api://konnektr-graph)
Authentication:IssuerNo—Expected JWT issuer (validated when set)
Authentication:MetadataAddressNo—Explicit OIDC metadata URL (overrides discovery from Authority)

When enabled, the API validates JWT tokens using:

  • Issuer validation (if Issuer is set)
  • Audience validation
  • Signing key validation
  • MapInboundClaims = false (preserves original claim types)

Authorization

Requires Authentication:Enabled = true.

KeyRequiredDefaultDescription
Authorization:EnabledYesfalseSet to true to enable permission-based authorization
Authorization:ProviderNoClaimsPermission provider: Claims (JWT claim) or Api (external API)
Authorization:PermissionsClaimNameNopermissionsName of the JWT claim holding permission strings
Authorization:RequiredScopesNo[]Array of required OAuth scopes (e.g., ["digitaltwins:read"])
Authorization:ScopesSupportedNo[]Array of supported OAuth scopes (for discovery)

API Provider Options

When Authorization:Provider = Api, configure these under Authorization:ApiProvider:

KeyRequiredDefaultDescription
ApiProvider:BaseUrlYes—Base URL of the external permissions API
ApiProvider:CheckEndpointNo/api/v1/permissions/checkEndpoint for permission checks
ApiProvider:ResourceNameNodigitaltwinsResource identifier sent to the permissions API
ApiProvider:CacheExpirationMinutesNo5How long to cache permission responses
ApiProvider:TimeoutSecondsNo10HTTP request timeout to the permissions API
ApiProvider:TokenEndpointIf OAuth—OAuth token endpoint for M2M client credentials flow
ApiProvider:AudienceIf OAuth—Audience for the M2M token
ApiProvider:ClientIdIf OAuth—Client ID for the M2M flow
ApiProvider:ClientSecretIf OAuth—Client secret for the M2M flow

When Api provider is used, the ClaimsPermissionProvider is also registered alongside the ApiPermissionProvider. Both are aggregated via CompositePermissionProvider — permissions from either source grant access.

CORS

KeyRequiredDefaultDescription
Cors:EnabledNofalseSet to true to enable CORS
Cors:AllowedOriginsIf enabled—Array of allowed origins (wildcard * is not supported)
Cors:AllowedMethodsNo["GET","POST","PUT","DELETE","OPTIONS"]Allowed HTTP methods
Cors:AllowedHeadersNo["*"]Allowed request headers

Rate Limiting

Rate limiting is enabled by default. Controlled by Parameters:RateLimitingEnabled.

Global Rate Limit

Applies to all endpoints as a per-user/IP safety net.

KeyDefaultDescription
Parameters:GlobalPermitLimit1000Max requests per window per user
Parameters:GlobalWindowSeconds1Window duration in seconds
Parameters:GlobalQueueLimit200Max queued requests when rate limited

Light Operations

Used for read operations (GET single items, list operations).

KeyDefaultDescription
Parameters:LightOperationsPermitLimit100Max requests per second
Parameters:LightOperationsWindowSeconds1Window in seconds
Parameters:LightOperationsQueueLimit50Queue capacity

Medium Operations

Used for queries and batch operations.

KeyDefaultDescription
Parameters:MediumOperationsPermitLimit50Max requests per second
Parameters:MediumOperationsWindowSeconds1Window in seconds
Parameters:MediumOperationsQueueLimit25Queue capacity

Heavy Operations

Used for create/update/delete operations.

KeyDefaultDescription
Parameters:HeavyOperationsPermitLimit20Max requests per second
Parameters:HeavyOperationsWindowSeconds1Window in seconds
Parameters:HeavyOperationsQueueLimit10Queue capacity

Admin Operations

Used for model management and job operations. Window is per-minute (not per-second).

KeyDefaultDescription
Parameters:AdminOperationsPermitLimit50Max requests per minute
Parameters:AdminOperationsWindowMinutes1Window in minutes
Parameters:AdminOperationsQueueLimit25Queue capacity

Weighted Query (Token Bucket)

Used for the /query endpoint. Each query consumes tokens proportional to its query-charge.

KeyDefaultDescription
Parameters:WeightedQueryTokenLimit1000Max token bucket capacity
Parameters:WeightedQueryQueueLimit100Queue capacity
Parameters:WeightedQueryReplenishSeconds1Replenishment period in seconds
Parameters:WeightedQueryTokensPerPeriod100Tokens added per replenishment period

Database Protection Middleware

Monitors and protects the database from overload. Controlled by Parameters:RateLimitingEnabled (the middleware only runs when rate limiting is enabled).

KeyDefaultDescription
Parameters:MaxConcurrentRequestsPerUser20Max concurrent requests per user/IP before 429
Parameters:MaxQueryComplexityPerWindow1000Max query complexity score per window before 429
Parameters:BaseQueryComplexity10Complexity score added per query endpoint request
Parameters:SlowRequestThresholdMs5000Logs a warning for requests exceeding this duration (ms)
Parameters:MetricsRetentionMinutes10How long to retain per-user metrics before cleanup
Parameters:QueryComplexityWindowMinutes1Time window for query complexity tracking

User ID Header Delegation

When Konnektr Graph runs behind an authenticating proxy (e.g., a proxy that validates Azure B2C tokens and forwards requests using a managed identity), the proxy can inject the original user's ID via an HTTP header. The API service uses this header value for authorization lookups and TrackLastUpdatedBy instead of the managed identity's claims.

KeyDefaultDescription
Parameters:UserIdHeaderName"" (disabled)HTTP header name to read the original user ID from (e.g., X-User-Id). Empty string disables the feature.
Parameters:UserIdHeaderRequiredfalseWhen true and UserIdHeaderName is set, requests missing the header receive a 401 Unauthorized response. When false, requests without the header fall back to the managed identity's claims (current behavior).

When enabled, a UserIdHeaderMiddleware runs in the request pipeline after authentication and before authorization. It creates a synthetic ClaimsIdentity with the header value as the sub, NameIdentifier, and Name claims, then prepends it to the ClaimsPrincipal. Original managed identity claims (permissions, roles, scp) are copied to the synthetic identity so permission providers continue to work.

See Security for details.

Import Jobs

KeyDefaultDescription
Parameters:JobsEnabledtrueSet to false to disable import job endpoints and blob storage

When jobs are enabled, blob storage services are registered for import/export of ND-JSON data:

  • AzureBlobStorageService — Azure Blob Storage (SAS URIs)
  • DefaultBlobStorageService — AWS S3, Google Cloud Storage, or local filesystem (routed by URI scheme)
  • JobResumptionService — background service (IHostedService) that resumes interrupted import jobs on startup

OpenAPI / Scalar

KeyRequiredDefaultDescription
OpenApi:EnabledNoOnly in DevelopmentSet to true to enable OpenAPI and Scalar UI in non-Development environments

Events Service

The Events Service (AgeDigitalTwins.Events) captures database changes via PostgreSQL logical replication (LISTEN/NOTIFY for telemetry) and routes them to configured sinks as CloudEvents.

Connection Strings

Falls back through this chain: GetConnectionString("agedb") → ConnectionStrings:agedb → AgeConnectionString.

KeyRequiredDefaultDescription
ConnectionStrings:agedbYes*—PostgreSQL connection string
AgeConnectionStringNo—Fallback connection string

Replication

KeyDefaultDescription
Parameters:AgePublicationage_pubPostgreSQL publication name for logical replication
Parameters:AgeReplicationSlotage_slotReplication slot name
Parameters:MaxBatchSize50Max events to batch from WAL changes
Parameters:WalReceiverTimeoutSeconds30Seconds without WAL message before declaring connection dead. Keep shorter than CNPG's WAL-receiver drain timeout for failover scenarios

Event Source / CloudEvents Source URI

KeyDefaultDescription
Parameters:CustomEventSourceDerived from connection string hostCustom URI for the CloudEvents source attribute

TrackLastUpdatedBy

KeyDefaultDescription
Parameters:TrackLastUpdatedByfalseWhen true, includes updatedBy fields in DataHistory CloudEvents from the $metadata.$lastUpdatedBy value

Event Sinks

Event sinks are configured under the EventSinks section. Each sink type supports multiple instances (configured as arrays).

Kafka

Configured under EventSinks:Kafka as an array.

KeyRequiredDescription
NameYesSink name (referenced by EventRoutes)
BrokerListYesKafka broker list (e.g., broker1:9092,broker2:9092)
TopicYesKafka topic name
SaslMechanismNoSASL mechanism: PLAIN or OAUTHBEARER
SaslUsernameIf PLAINSASL username
SaslPasswordIf PLAINSASL password
SecurityProtocolNoDefaults to SaslSsl
TenantIdIf OAUTHBEARERAzure AD tenant ID (for ClientSecretCredential)
ClientIdIf OAUTHBEAREROAuth client ID
ClientSecretIf OAUTHBEAREROAuth client secret
TokenEndpointIf OAUTHBEAREROAuth token endpoint
AuthenticationTypeNoNot used for Kafka (uses SASL config)
ScopeNoEvent scope filter
EventTypeMappingsNoMaps SinkEventType to custom topic names

MQTT

Configured under EventSinks:MQTT as an array.

KeyRequiredDefaultDescription
NameYes—Sink name
BrokerYes—MQTT broker hostname
PortYes—MQTT broker port
TopicYes—MQTT topic
ClientIdYes—MQTT client ID
UsernameYes—MQTT username
PasswordYes—MQTT password
ProtocolVersionNo5.0.0MQTT protocol version (3.1.0, 3.1.1, or 5.0.0)
TenantIdNo—Azure AD tenant ID (for OAuth token refresh)
ClientId (OAuth)No—OAuth client ID
ClientSecretNo—OAuth client secret
TokenEndpointNo—OAuth token endpoint
ScopeNo—Event scope filter
EventTypeMappingsNo—Maps SinkEventType to custom topic names

Webhook

Configured under EventSinks:Webhook as an array.

KeyRequiredDescription
NameYesSink name
UrlYesWebhook endpoint URL
AuthenticationTypeYesAuth type: None, Basic, Bearer, ApiKey
UsernameIf Basic AuthUsername
PasswordIf Basic AuthPassword
TokenIf Bearer AuthStatic bearer token
HeaderNameIf ApiKeyHTTP header name
HeaderValueIf ApiKeyHTTP header value
TokenEndpointIf OAuthOAuth token endpoint
ClientIdIf OAuthOAuth client ID
ClientSecretIf OAuthOAuth client secret
ScopeNoEvent scope filter
EventTypeMappingsNoMaps SinkEventType to custom topics

NATS

Configured under EventSinks:NATS as an array.

KeyRequiredDefaultDescription
NameYes—Sink name (referenced by EventRoutes)
UrlYes—NATS server URL (e.g., nats://nats-cluster:4222)
SubjectYes—NATS subject to publish events to
UsernameNo—NATS username (basic auth)
PasswordNo—NATS password (basic auth)
TokenNo—Static token for NATS token authentication
AuthenticationTypeNo—Set to OAuth to use OAuth 2.0 token exchange (requires TokenEndpoint + ClientId + ClientSecret)
ScopeIf OAuth—OAuth scope for token request
TlsEnabledNofalseEnable TLS for NATS connection
TlsSkipVerifyNofalseSkip TLS certificate verification (dev only)
JetStreamNofalseEnable JetStream for durable, at-least-once delivery
StreamNameIf JetStream—JetStream stream name (must exist if JetStream is true)
StreamReplicasNo1JetStream stream replication factor
StreamMaxAgeNo72hJetStream stream max age (e.g., 72h, 7d)
UseBinaryModeNotrueWhen true (default), publishes CloudEvents in binary content mode with CE headers as NATS headers. When false, uses structured content mode with full CloudEvents JSON envelope
TokenEndpointIf OAuth—OAuth token endpoint URL
TenantIdNo—Azure AD tenant ID (for ClientSecretCredential)
ClientIdIf OAuth—OAuth client ID
ClientSecretIf OAuth—OAuth client secret
EventTypeMappingsNo—Maps SinkEventType to custom subjects

Azure Data Explorer (Kusto)

Configured under EventSinks:Kusto as an array.

KeyRequiredDescription
NameYesSink name
IngestionUriYesKusto cluster ingestion URI (e.g., https://ingest-cluster.kusto.windows.net)
DatabaseYesKusto database name
PropertyEventsTableNoTable name for property change events (AdtPropertyEvents by convention)
TwinLifeCycleEventsTableNoTable name for twin lifecycle events (AdtTwinLifeCycleEvents by convention)
RelationshipLifeCycleEventsTableNoTable name for relationship lifecycle events (AdtRelationshipLifeCycleEvents by convention)
TenantIdYesAzure AD tenant ID
ClientIdYesService principal client ID
ClientSecretYesService principal client secret
TrackLastUpdatedByNoInherits from Parameters:TrackLastUpdatedBy. When true, adds an UpdatedBy column mapping
ScopeNoEvent scope filter
EventTypeMappingsNoMaps SinkEventType to custom tables

PostgreSQL / TimescaleDB

Configured under EventSinks:Postgres as an array.

KeyRequiredDefaultDescription
NameYes—Sink name
ConnectionStringYes—Npgsql connection string (Host=…;Port=…;Database=…;Username=…;Password=…)
SchemaNopublicSchema for the history tables (created if missing)
PropertyEventsTableNoadt_property_eventsTable for property change events
TwinLifeCycleEventsTableNoadt_twin_lifecycle_eventsTable for twin lifecycle events
RelationshipLifeCycleEventsTableNoadt_relationship_lifecycle_eventsTable for relationship lifecycle events
TrackLastUpdatedByNoInherits from Parameters:TrackLastUpdatedByWhen true, adds an updated_by column to every history table
EventTypeMappingsNo—Maps SinkEventType to custom CloudEvent types

The sink creates its tables (and the schema, when configured) on first use and, when the timescaledb extension is present, converts them to hypertables partitioned on time_stamp. See the PostgreSQL data history guide for schema details and temporal query examples.

Event Routes

Configured under EventRoutes as an array. Routes map event types to sinks.

KeyRequiredDescription
SinkNameYesMust match a sink's Name
EventFormatNoOutput format: EventNotification (default) or DataHistory
TypeMappingsNoDictionary mapping SinkEventType to destination-specific keys (e.g., Kafka topic, Kusto table)

SinkEventType Enum

ValueDescription
TwinCreateDigital twin created
TwinUpdateDigital twin updated
TwinDeleteDigital twin deleted
RelationshipCreateRelationship created
RelationshipUpdateRelationship updated
RelationshipDeleteRelationship deleted
TelemetryTelemetry message published
PropertyEventIndividual property change (DataHistory format)
TwinLifecycleTwin create/delete (DataHistory format)
RelationshipLifecycleRelationship create/delete (DataHistory format)

EventFormat Enum

ValueDescription
EventNotificationFull CloudEvents format with complete details
DataHistoryOptimized format for time-series storage
TelemetryTelemetry message format

Dead Letter Queue

The Events Service maintains a dead letter queue table (digitaltwins_eventing.dead_letter_queue in the same PostgreSQL database) for events that fail to deliver after all retries.

Schema is automatically created on startup. No user configuration required.

Credential Resolution for Sinks

Credentials are resolved via CredentialFactory using this priority:

  1. If TokenEndpoint + ClientId + ClientSecret are provided → GenericClientCredential (generic OAuth2)
  2. If ClientId + ClientSecret are provided (with optional TenantId) → ClientSecretCredential (Azure AD)
  3. If none of the above → DefaultAzureCredential (Azure-managed identity fallback)

Common Configuration

Both services use AddServiceDefaults() from AgeDigitalTwins.ServiceDefaults.

OpenTelemetry

KeyDescription
OTEL_EXPORTER_OTLP_ENDPOINTIf set, enables OTLP exporter for OpenTelemetry traces and metrics

OpenTelemetry is configured with:

  • Metrics: ASP.NET Core instrumentation, HTTP client instrumentation, runtime instrumentation, custom meters (AgeDigitalTwins.SDK, AgeDigitalTwins.Events)
  • Tracing: ASP.NET Core instrumentation, HTTP client instrumentation, custom sources (AgeDigitalTwins.SDK, AgeDigitalTwins.Events)
  • Logging: OpenTelemetry logging with formatted messages and scopes

Health Checks

Both services expose:

  • GET /health — All health checks pass (ready to accept traffic). Anonymous access.
  • GET /alive — Only live-tagged checks pass (is the process alive?). Anonymous access.

API Service health checks:

  • PostgreSQL connection (via Aspire Npgsql integration)

Events Service health checks:

  • replication — AgeDigitalTwinsReplication.IsHealthy (tagged: live)
  • event_sinks — All registered IEventSink.IsHealthy (tagged: live)

Logging

Standard ASP.NET Core logging configuration applies. Key namespaces for debugging:

NamespacePurpose
Microsoft.AspNetCore.AuthenticationJWT token validation details
Microsoft.AspNetCore.AuthorizationAuthorization decisions
AgeDigitalTwins.ServiceDefaults.AuthorizationPermission provider operations
AgeDigitalTwins.ApiService.MiddlewareDatabase protection, rate limiting
AgeDigitalTwins.Events.Core.ServicesReplication, event consumer

Example Configuration

Minimal (No Authentication, No Event Sinks)

{
  "ConnectionStrings": {
    "agedb": "Host=localhost;Port=5432;Database=app;Username=app;Password=app"
  },
  "Parameters": {
    "AgeGraphName": "digitaltwins",
    "UseCnpgAge": true
  }
}

Full API Service with Auth and Rate Limiting

{
  "ConnectionStrings": {
    "agedb": "Host=localhost;Port=5432;Database=app;Username=app;Password=app"
  },
  "Parameters": {
    "AgeGraphName": "digitaltwins",
    "UseCnpgAge": true,
    "ModelCacheExpirationSeconds": 30,
    "MaxPoolSize": 50,
    "TrackLastUpdatedBy": true,
    "JobsEnabled": true,
    "RateLimitingEnabled": true,
    "GlobalPermitLimit": 500,
    "LightOperationsPermitLimit": 50,
    "HeavyOperationsPermitLimit": 10
  },
  "Authentication": {
    "Enabled": true,
    "Authority": "https://your-tenant.auth0.com/",
    "Audience": "api://konnektr-graph",
    "Issuer": "https://your-tenant.auth0.com/"
  },
  "Authorization": {
    "Enabled": true,
    "Provider": "Claims",
    "PermissionsClaimName": "permissions"
  },
  "Cors": {
    "Enabled": true,
    "AllowedOrigins": ["https://myapp.example.com"],
    "AllowedMethods": ["GET", "POST", "PUT", "DELETE"]
  }
}

Full Events Service with Kafka, Kusto, and NATS Sinks

{
  "ConnectionStrings": {
    "agedb": "Host=localhost;Port=5432;Database=app;Username=app;Password=app"
  },
  "Parameters": {
    "AgePublication": "age_pub",
    "AgeReplicationSlot": "age_slot",
    "MaxBatchSize": 100,
    "WalReceiverTimeoutSeconds": 30,
    "TrackLastUpdatedBy": true
  },
  "EventSinks": {
    "Kafka": [
      {
        "Name": "production-kafka",
        "BrokerList": "broker1:9092,broker2:9092",
        "Topic": "digitaltwins-events",
        "SaslMechanism": "PLAIN",
        "SaslUsername": "user",
        "SaslPassword": "pass",
        "SecurityProtocol": "SaslSsl"
      }
    ],
    "NATS": [
      {
        "Name": "realtime-nats",
        "Url": "nats://nats-cluster:4222",
        "Subject": "graph.events",
        "JetStream": true,
        "StreamName": "graph-events",
        "UseBinaryMode": true,
        "Token": "my-nats-token"
      }
    ],
    "Kusto": [
      {
        "Name": "archive-kusto",
        "IngestionUri": "https://ingest-cluster.kusto.windows.net",
        "Database": "DigitalTwinsHistory",
        "TenantId": "tenant-id",
        "ClientId": "sp-client-id",
        "ClientSecret": "sp-client-secret"
      }
    ],
    "Postgres": [
      {
        "Name": "PostgresDataHistory",
        "ConnectionString": "Host=postgres;Port=5432;Database=history;Username=graph;Password=graph",
        "Schema": "public",
        "TrackLastUpdatedBy": true
      }
    ]
  },
  "EventRoutes": [
    {
      "SinkName": "production-kafka",
      "EventFormat": "EventNotification",
      "TypeMappings": {
        "TwinCreate": "twin-created",
        "TwinUpdate": "twin-updated",
        "TwinDelete": "twin-deleted",
        "Telemetry": "twin-telemetry"
      }
    },
    {
      "SinkName": "realtime-nats",
      "EventFormat": "EventNotification"
    },
    {
      "SinkName": "archive-kusto",
      "EventFormat": "DataHistory"
    }
  ]
}

Environment Variable Reference

All configuration keys can be set as environment variables. The __ (double underscore) replaces : (colon) as the hierarchy separator.

Environment VariableCorresponding Config Key
ConnectionStrings__agedbConnectionStrings:agedb
Parameters__AgeGraphNameParameters:AgeGraphName
Parameters__UseCnpgAgeParameters:UseCnpgAge
Parameters__TrackLastUpdatedByParameters:TrackLastUpdatedBy
Parameters__MaxPoolSizeParameters:MaxPoolSize
Parameters__RateLimitingEnabledParameters:RateLimitingEnabled
Parameters__JobsEnabledParameters:JobsEnabled
Authentication__EnabledAuthentication:Enabled
Authentication__AuthorityAuthentication:Authority
Authentication__AudienceAuthentication:Audience
Authentication__IssuerAuthentication:Issuer
Authorization__EnabledAuthorization:Enabled
Authorization__ProviderAuthorization:Provider
Authorization__PermissionsClaimNameAuthorization:PermissionsClaimName
Parameters__AgePublicationParameters:AgePublication
Parameters__AgeReplicationSlotParameters:AgeReplicationSlot
Parameters__UserIdHeaderNameParameters:UserIdHeaderName
Parameters__UserIdHeaderRequiredParameters:UserIdHeaderRequired
Parameters__WalReceiverTimeoutSecondsParameters:WalReceiverTimeoutSeconds
OTEL_EXPORTER_OTLP_ENDPOINTOpenTelemetry OTLP exporter endpoint

On this page