Configuration
Set CONFIG_PATH to an absolute configuration file path. Without it, the file
loader searches for config.yaml or another supported config file format in
the process's current directory and its parents. The application validates the
loaded configuration at startup.
Environment variables override file settings. Use the uppercase TSG__ prefix,
double underscores between path segments and snake case for camel-case keys.
For example, TSG__SERVER__PUBLIC_ADDRESS overrides server.publicAddress.
Execution owners and authentication
Every worker requires auth.enabled: true, stable controlPlane.dataplaneId and
controlPlane.controlplaneId, and a nonempty controlPlane.executionScopes list.
Each entry contains the verified issuer, logical controlPlaneId and canonical
tenantId returned by Tenant Management. A worker serving one owner uses one entry;
a worker serving several owners lists all of them. There is no dedicated/shared
mode switch or self-registration. Slugs and participant DIDs cannot replace tenant
UUIDs.
Use strict OAuth token verification with a trusted OpenID issuer. The signaling
JWT audience is the worker's dataplaneId. The operator browser client and its
auth.expectedAudience are separate. Global management requires an authenticated
human explicitly listed in management.operatorPrincipals. Tenant or workload
grants do not confer global operator access; an empty operator allowlist denies
access.
Provision a registration for each tenant through the managed control-plane
profile, with the worker's actual API endpoint and executionLease: true. Managed
provisioning supplies the tenant-bound signaling credential. Execution leases are
bounded by the verified signaling JWT expiry and the control plane's authorization
deadline. See execution leases.
The Helm example and managed local sample show the full relationship between Tenant Management, SSO Bridge, Control Plane and worker. The local sample generates its worker configuration only after the operator selects actual provisioned canonical tenant IDs.
Configuration parameters
| Key | Required | Type | Description | Default |
|---|---|---|---|---|
BackendEgressRule | ||||
backendEgress | BackendEgressRule[] | Operator-controlled backend egress rules; no rules means no backend access | [] | |
backendEgress[].url | Yes | String | Allowed backend URL prefix for this execution owner (origin and path) | |
backendEgress[].addresses | Yes | String | Allowed resolved backend IP addresses or CIDR ranges | |
backendEgress[].issuer | Yes | String | Verified signaling issuer | |
backendEgress[].controlPlaneId | Yes | String | Logical control-plane client identity | |
backendEgress[].tenantId | Yes | String | Canonical tenant UUID | |
ManagementConfig | ||||
management | ManagementConfig | Worker global management policy | ||
OperatorPrincipal | ||||
management.operatorPrincipals | OperatorPrincipal[] | Global human operators allowed to inspect this worker; tenant grants never confer operator access | [] | |
management.operatorPrincipals[].issuer | Yes | String | Verified operator issuer | |
management.operatorPrincipals[].subject | Yes | String | Verified operator subject | |
DataAccessConfig | ||||
dataAccess | DataAccessConfig | HTTP JWT access and refresh grant configuration | ||
dataAccess.signingKey | String | Private asymmetric signing JWK as JSON; persist across restarts | ||
dataAccess.signingKeyPath | String | Mounted private signing JWK file | ||
dataAccess.previousPublicKeys | String | Previous public JWKs as JSON strings; retain for the maximum outstanding refresh grant lifetime | [] | |
dataAccess.accessTokenLifetime | Number | Access token lifetime in seconds | 300 | |
dataAccess.refreshTokenLifetime | Number | Refresh grant maximum lifetime in seconds, preserved across rotation | 86400 | |
DatabaseConfig | ||||
db | Yes | DatabaseConfig | Database configuration | |
db.retryAttempts | Number | Connection attempts during application startup, three seconds apart | 10 | |
db.type | Yes | "sqlite" | "postgres" | Type of database | |
db.database | Yes | String | Name of the database | |
db.synchronize | Boolean | Synchronize database schema | false | |
db{type=sqlite} | Yes | SQLiteConfig | Database configuration | |
db{type=sqlite}.retryAttempts | Number | Connection attempts during application startup, three seconds apart | 10 | |
db{type=sqlite}.type | "sqlite" | "postgres" | Type of database | "sqlite" | |
db{type=sqlite}.database | Yes | String | Name of the database | |
db{type=sqlite}.synchronize | Boolean | Synchronize database schema | false | |
db{type=postgres} | Yes | PostgresConfig | Database configuration | |
db{type=postgres}.host | Yes | String | Host of the database | |
db{type=postgres}.port | Yes | Number | Port of the database | |
db{type=postgres}.username | Yes | String | Username of the database | |
db{type=postgres}.password | Yes | String | Password of the database | |
db{type=postgres}.ssl | Object | SSL configuration of the database | false | |
db{type=postgres}.retryAttempts | Number | Connection attempts during application startup, three seconds apart | 10 | |
db{type=postgres}.type | "sqlite" | "postgres" | Type of database | "postgres" | |
db{type=postgres}.database | Yes | String | Name of the database | |
db{type=postgres}.synchronize | Boolean | Synchronize database schema | false | |
ServerConfig | ||||
server | ServerConfig | Server configuration | ||
server.listen | String | IP address the server listens on | "0.0.0.0" | |
server.port | Number | Port the server listens on | 3000 | |
server.publicDomain | String | Public domain of the server | "localhost" | |
server.publicAddress | String | Public address of the server | "http://localhost:3000" | |
server.subPath | String | Sub path of the server | ||
AuthConfig | ||||
auth | Yes | AuthConfig | Management authentication configuration | |
auth.signalingId | String | Receiving plane identity for signaling tokens. Defaults to clientId. | ||
auth.expectedIssuer | String | Expected API token issuer; defaults to the discovered OpenID issuer | ||
auth.expectedAudience | String | Expected API token audience; defaults to clientId. | ||
auth.enabled | Boolean | Enable authentication | true | |
auth.openIdConfigurationURL | String | OpenID configuration URL | ||
auth.callbackURL | URL | Callback URL the auth service will redirect users | ||
auth.redirectURL | URL | Redirect URL to UI after login/logout | ||
auth.clientId | String | Client ID | ||
auth.clientSecret | String | Client secret (required for client_secret_post authentication) | ||
auth.tokenEndpointAuthMethod | "client_secret_post" | "private_key_jwt" | Token endpoint authentication method: client_secret_post (default) or private_key_jwt | "client_secret_post" | |
auth.privateKeyJwk | Object | Private key in JWK format for private_key_jwt authentication. Alternative to privateKeyJwkFile. | ||
auth.privateKeyJwkFile | String | Path to file containing private key JWK for private_key_jwt authentication. Alternative to privateKeyJwk. | ||
auth.permissionPath | String | JSON path to extract permissions from the token | "$.permissions[*]" | |
ControlPlaneConfig | ||||
controlPlane | Yes | ControlPlaneConfig | Control plane configuration | |
controlPlane.controlplaneId | Yes | String | Logical control-plane client identity verified on signaling | |
controlPlane.dataplaneId | Yes | String | Stable worker identity and audience for authenticated signaling | |
ExecutionScopeConfig | ||||
controlPlane.executionScopes | ExecutionScopeConfig[] | Exact execution owners accepted by this worker. Required on signaling servers; split runners use their bridge assignments | [] | |
controlPlane.executionScopes[].issuer | Yes | String | Verified signaling issuer | |
controlPlane.executionScopes[].controlPlaneId | Yes | String | Logical control-plane client identity | |
controlPlane.executionScopes[].tenantId | Yes | String | Canonical tenant UUID | |
LoggingConfig | ||||
logging | LoggingConfig | Logging configuration | ||
logging.debug | Boolean | Enable debug request logging | false | |
logging.serverLogging | "always" | "onClientError" | "onServerError" | "never" | Server logging configuration | "onServerError" | |
logging.clientLogging | "always" | "onClientError" | "onServerError" | "never" | Client logging configuration | "onClientError" | |
RuntimeConfig | ||||
runtime | Yes | RuntimeConfig | Runtime configuration | |
runtime.color | String | Primary UI color | "#3B8BF6" | |
runtime.lightThemeUrl | String | Light theme logo URL | ||
runtime.darkThemeUrl | String | Dark theme logo URL | ||
authorizationHeader | String | Authorization header used in provider proxy | "Authorization" | |
AuditModuleConfig | ||||
audit | AuditModuleConfig | Audit logging configuration | ||
audit.enabled | Boolean | Enable audit logging | true | |
audit.minSeverity | "debug" | "info" | "warning" | "error" | "critical" | Minimum severity level to log | "info" | |
audit.logDenied | Boolean | Always log denied access attempts regardless of action type | true | |
audit.logDelegated | Boolean | Log delegated access attempts when enabled, while still respecting action-specific success filters | true | |
audit.logMutations | Boolean | Log successful mutation actions (create, update, delete, manage) | true | |
audit.logExecute | Boolean | Log successful execute actions | false | |
audit.logReads | Boolean | Log successful read actions — disabled by default as reads are frequent and rarely relevant for auditing | false | |
audit.sensitiveResources | Array | Resources logged regardless of minimum severity, while still respecting action-specific success filters | ["w.key","w.credential","sso.user"] | |
AuditHandlersConfig | ||||
audit.handlers | AuditHandlersConfig | Handler configuration | ||
audit.handlers.console | Boolean | Enable console audit log handler | false | |
audit.handlers.database | Boolean | Enable database audit log handler | true | |
audit.handlers.otlp | Boolean | Enable OTLP audit log handler | false | |
OtlpAuditHandlerConfig | ||||
audit.otlp | OtlpAuditHandlerConfig | OTLP audit log handler configuration | ||
audit.otlp.url | String | OTLP HTTP logs endpoint URL | "http://localhost:4318/v1/logs" | |
audit.otlp.headers | Object | Additional HTTP headers to include in OTLP requests | ||
audit.otlp.timeoutMillis | Number | OTLP export timeout in milliseconds | 5000 | |
audit.otlp.concurrencyLimit | Number | Maximum number of concurrent OTLP export requests | 1 | |
audit.otlp.serviceName | String | Service name included on OTLP log attributes | "tsg-dsp-api" | |
audit.otlp.serviceVersion | String | Optional service version included on OTLP log attributes |