Skip to main content
Version: Next

Configuration

In this section, the configuration of the control plane is explained. Configuration is used based on a config.yaml file which should be placed in the apps/backend/src folder. This config.yaml file is loaded when booting the application. The values get type checked, and it gives a clear error message if there is a configuration field missing or provided incorrectly. Next to the config.yaml file, you can also set environment variables. These override the values that are listed in the config.yaml file.

Databases

By default, the development database is sqlite. We use postgres databases for production type instances of the control planes.

Authentication

Authentication for frontend services can be done via the SSO Bridge. This helps users who need to login to several components to authenticate themselves faster.

Tenants

A control-plane process serves one or more tenants. A tenant is a dataspace participant in its own right: it has its own DID and wallet configuration (iam), its own catalog, its own registry crawl, and its own data. There is no special "default" tenant — the first tenant is declared exactly like the hundredth, under initTenants, and at least one entry is required.

initTenants:
- name: Alfa
slug: alfa
iam:
type: tsg
didId: did:web:wallet.example
walletUrl: https://wallet.example
siopUrl: https://wallet.example/management/dcp/holder/token
verifyUrl: https://wallet.example/management/dcp/verifier/verify
initCatalog:
participantId: did:web:wallet.example
creator: did:web:wallet.example
publisher: did:web:wallet.example
title: Alfa
description: Alfa connector

Addressing

Every tenant is addressed by its slug, whether the process serves one tenant or a hundred:

  • DSP protocol endpoints: https://cp.example/tenants/<slug>/...
  • Management API: X-Tenant-Slug: <slug> (or X-Tenant-Id) on every call.

A request that carries no tenant (no path segment and no header) resolves to nothing: management endpoints answer 403 and DSP protocol endpoints answer 404, rather than silently picking a participant identity. The control-plane UI has no tenant switcher yet, so it is single-tenant-only for now.

Upgrading from a pre-multi-tenancy deployment

The multi-tenancy migration backfilled all existing rows onto a tenant with slug default. To keep that data reachable, either:

  • keep slug: default in your new initTenants entry — the bootstrap adopts the existing row and nothing moves; or
  • rename the tenant first with PATCH /management/tenants/default and then declare the new slug.

Declaring a fresh slug without renaming leaves the old data on an unmanaged tenant row, and the connector comes up with an empty catalog. The control plane logs a warning at boot for any tenant row that no initTenants entry claims.

DCP presentation query mode

Incoming DSP requests are verified with the tenant's wallet. By default (dcpPresentationQueryMode: presentation-definition) the control plane sends a Presentation Definition built from typeFilter, issuerFilter and customFields. Counterparties such as EDC IdentityHub only support scope queries; for them, set dcpPresentationQueryMode: scope. Incoming requests are then verified with dcpRequiredScopes. If omitted, it falls back to dcpDefaultScopes, which also supplies the scopes in outgoing tokens. Set the two lists separately when you need different incoming and outgoing scopes. Explicit agreement scopes are unchanged. Returned credentials must still satisfy typeFilter, issuerFilter and customFields and be issued to the requester.

In scope mode, every tenant must have a non-empty effective incoming scope list. An explicitly empty dcpRequiredScopes does not fall back to the defaults. The control plane rejects invalid configurations at startup. When upgrading a deployment with dcpPresentationQueryMode: scope, configure either dcpRequiredScopes or a non-empty dcpDefaultScopes before restarting.

iam:
type: tsg
dcpPresentationQueryMode: scope
dcpDefaultScopes:
- org.eclipse.dspace.dcp.vc.type:ParticipantCredential:read
dcpRequiredScopes:
- org.eclipse.dspace.dcp.vc.type:MembershipCredential:read

Transfer context for data planes

When a provider accepts a transfer request, it stores a snapshot of the transfer context and sends it to the data plane in every signaling message for that transfer:

  • participantId and counterPartyId: the agreement assigner and the verified requester.
  • dataspaceContext: iam.dataspaceContext (default dataspace-protocol-http:2025-1).
  • claims: a flat projection of the requester's verified credentials, limited to iam.transferClaims. When omitted, the default allow-list is subjectId, credentialTypes and issuers. A configured list replaces all defaults; transferClaims: [] sends no claims. This does not remove the separate counterPartyId field. List claims collect all values; a single claim with different values across credentials is left out.

To add membership.status while retaining all default claims, include the complete list. Both issuer mappings are needed to support string and object issuer forms:

iam:
transferClaims:
- name: subjectId
path: credentialSubject.id
- name: credentialTypes
path: type
list: true
- name: issuers
path: issuer
list: true
- name: issuers
path: issuer.id
list: true
- name: membership.status
path: credentialSubject.membership.status

Configuration parameters

KeyRequiredTypeDescriptionDefault
DatabaseConfig
dbYesDatabaseConfigDatabase configuration
db.typeYes"sqlite" | "postgres"Type of database
db.databaseYesStringName of the database
db.synchronizeBooleanSynchronize database schema
db{type=sqlite}YesSQLiteConfigDatabase configuration
db{type=sqlite}.type"sqlite" | "postgres"Type of database"sqlite"
db{type=sqlite}.databaseYesStringName of the database
db{type=sqlite}.synchronizeBooleanSynchronize database schema
db{type=postgres}YesPostgresConfigDatabase configuration
db{type=postgres}.hostYesStringHost of the database
db{type=postgres}.portYesNumberPort of the database
db{type=postgres}.usernameYesStringUsername of the database
db{type=postgres}.passwordYesStringPassword of the database
db{type=postgres}.sslUnknownSSL configuration of the database
db{type=postgres}.type"sqlite" | "postgres"Type of database"postgres"
db{type=postgres}.databaseYesStringName of the database
db{type=postgres}.synchronizeBooleanSynchronize database schema
ServerConfig
serverServerConfigServer configuration
server.listenStringIP address the server listens on"0.0.0.0"
server.portNumberPort the server listens on3000
server.publicDomainStringPublic domain of the server"localhost"
server.publicAddressStringPublic address of the server"http://localhost:3000"
server.subPathStringSub path of the server
AuthConfig
authYesAuthConfigManagement authentication configuration
auth.enabledBooleanEnable authenticationtrue
auth.openIdConfigurationURLStringOpenID configuration URL
auth.callbackURLURLCallback URL the auth service will redirect users
auth.redirectURLURLRedirect URL to UI after login/logout
auth.clientIdStringClient ID
auth.clientSecretStringClient 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.privateKeyJwkObjectPrivate key in JWK format for private_key_jwt authentication. Alternative to privateKeyJwkFile.
auth.privateKeyJwkFileStringPath to file containing private key JWK for private_key_jwt authentication. Alternative to privateKeyJwk.
auth.permissionPathStringJSON path to extract permissions from the token"$.permissions[*]"
RegistryConfig
registryYesRegistryConfigRegistry configuration
registry.useRegistryYesBooleanUse registry to crawl catalogs
registry.registryUrlStringURL of the registry
registry.registryDidStringDID of the registry
registry.registryIntervalInMillisecondsNumberInterval in milliseconds to fetch registry30000
InitTenantConfig
initTenantsYesInitTenantConfig[]Tenants served by this process, created on startup. At least one tenant must be declared; every tenant is addressed as /tenants/:slug/...
IamConfig
initTenants[].iamYesIamConfigIAM/wallet configuration for this tenant
initTenants[].iam.typeYes"tsg" | "dev"Type of IAM service
initTenants[].iam.didIdYesStringDID identifier of the IAM service
initTenants[].iam.protocolStringProtocol of the IAM service"DCP"
initTenants[].iam.versionStringProtocol of the IAM service"1.0"
initTenants[].iam.profileStringProfiles of the IAM service["vc11-bssl/jsonld"]
initTenants[].iam.dataspaceContextStringDataspace context sent to data planes in signaling messages, e.g. the DSP protocol or a dataspace id"dataspace-protocol-http:2025-1"
TransferClaimConfig
initTenants[].iam.transferClaimsTransferClaimConfig[]Allow-listed claims projected from the counterparty's verified credentials and sent to data planes. When omitted, defaults to subjectId, credentialTypes and issuers. A configured list replaces all defaults; [] sends no claims.
initTenants[].iam.transferClaims[].nameYesStringClaim name sent to data planes
initTenants[].iam.transferClaims[].pathYesStringDotted path into a verified credential, e.g. credentialSubject.membership.status
initTenants[].iam.transferClaims[].listBooleanCollect all values as a list; otherwise conflicting values omit the claim
initTenants[].iam{type=dev}YesDevWalletConfigIAM/wallet configuration for this tenant
initTenants[].iam{type=dev}.type"tsg" | "dev"Type of IAM service"dev"
initTenants[].iam{type=dev}.didIdYesStringDID identifier of the IAM service
initTenants[].iam{type=dev}.protocolStringProtocol of the IAM service"DCP"
initTenants[].iam{type=dev}.versionStringProtocol of the IAM service"1.0"
initTenants[].iam{type=dev}.profileStringProfiles of the IAM service["vc11-bssl/jsonld"]
initTenants[].iam{type=dev}.dataspaceContextStringDataspace context sent to data planes in signaling messages, e.g. the DSP protocol or a dataspace id"dataspace-protocol-http:2025-1"
TransferClaimConfig
initTenants[].iam{type=dev}.transferClaimsTransferClaimConfig[]Allow-listed claims projected from the counterparty's verified credentials and sent to data planes. When omitted, defaults to subjectId, credentialTypes and issuers. A configured list replaces all defaults; [] sends no claims.
initTenants[].iam{type=dev}.transferClaims[].nameYesStringClaim name sent to data planes
initTenants[].iam{type=dev}.transferClaims[].pathYesStringDotted path into a verified credential, e.g. credentialSubject.membership.status
initTenants[].iam{type=dev}.transferClaims[].listBooleanCollect all values as a list; otherwise conflicting values omit the claim
initTenants[].iam{type=tsg}YesTsgWalletConfigIAM/wallet configuration for this tenant
initTenants[].iam{type=tsg}.walletUrlYesURLURL of the wallet management endpoint
initTenants[].iam{type=tsg}.siopUrlYesURLURL of the SIOP token endpoint
initTenants[].iam{type=tsg}.verifyUrlYesURLURL of the verification endpoint
initTenants[].iam{type=tsg}.typeFilterStringCredential type filter used as default
initTenants[].iam{type=tsg}.issuerFilterStringIssuer filter used as default
initTenants[].iam{type=tsg}.customFieldsArrayCustom presentation definition fields
initTenants[].iam{type=tsg}.walletTenantSlugStringTenant slug sent as X-Tenant-Slug header to the wallet (multi-tenant mode)
initTenants[].iam{type=tsg}.dcpPresentationQueryMode"presentation-definition" | "scope"DCP presentation query mode. The default expands TSG scopes to a Presentation Definition; scope forwards the requested scopes unchanged."presentation-definition"
initTenants[].iam{type=tsg}.dcpDefaultScopesStringDCP scopes included in every outgoing self-issued token. Also used for incoming scope queries when dcpRequiredScopes is omitted.[]
initTenants[].iam{type=tsg}.dcpRequiredScopesStringScopes requested to verify incoming DSP requests in scope query mode. Defaults to dcpDefaultScopes when omitted. The effective list must be non-empty in scope mode. Does not change outgoing token scopes or explicit agreement scopes.
DcpScopeMappingConfig
initTenants[].iam{type=tsg}.dcpScopeMappingsDcpScopeMappingConfig[]Fixed DCP scopes activated by exact ODRL left-operand matches
initTenants[].iam{type=tsg}.dcpScopeMappings[].leftOperandYesStringExact ODRL left operand that activates this DCP scope
initTenants[].iam{type=tsg}.dcpScopeMappings[].scopeYesStringDCP credential scope granted for matching policies
initTenants[].iam{type=tsg}.type"tsg" | "dev"Type of IAM service"tsg"
initTenants[].iam{type=tsg}.didIdYesStringDID identifier of the IAM service
initTenants[].iam{type=tsg}.protocolStringProtocol of the IAM service"DCP"
initTenants[].iam{type=tsg}.versionStringProtocol of the IAM service"1.0"
initTenants[].iam{type=tsg}.profileStringProfiles of the IAM service["vc11-bssl/jsonld"]
initTenants[].iam{type=tsg}.dataspaceContextStringDataspace context sent to data planes in signaling messages, e.g. the DSP protocol or a dataspace id"dataspace-protocol-http:2025-1"
TransferClaimConfig
initTenants[].iam{type=tsg}.transferClaimsTransferClaimConfig[]Allow-listed claims projected from the counterparty's verified credentials and sent to data planes. When omitted, defaults to subjectId, credentialTypes and issuers. A configured list replaces all defaults; [] sends no claims.
initTenants[].iam{type=tsg}.transferClaims[].nameYesStringClaim name sent to data planes
initTenants[].iam{type=tsg}.transferClaims[].pathYesStringDotted path into a verified credential, e.g. credentialSubject.membership.status
initTenants[].iam{type=tsg}.transferClaims[].listBooleanCollect all values as a list; otherwise conflicting values omit the claim
InitCatalog
initTenants[].initCatalogInitCatalogInitial catalog configuration for this tenant
initTenants[].initCatalog.participantIdYesStringParticipant id of the catalog
initTenants[].initCatalog.creatorYesStringCreator of the catalog
initTenants[].initCatalog.publisherYesStringPublisher of the catalog
initTenants[].initCatalog.titleYesStringTitle of the catalog
initTenants[].initCatalog.descriptionYesStringDescription of the catalog
initTenants[].initCatalog.datasetsStringSerialized initial datasets
initTenants[].nameYesStringDisplay name of the tenant
initTenants[].slugYesStringURL-safe slug for the tenant
InitTenantMemberConfig
initTenants[].membersInitTenantMemberConfig[]Users granted access to this tenant on startup
initTenants[].members[].identifierYesStringUsername, email or auth subject id (sub) of the user
initTenants[].members[].usernameStringDisplay name to record for the user, when known
initTenants[].members[].role"owner" | "admin" | "member"Role granted to the user within the tenant"member"
PolicyConfig
defaultPolicyPolicyConfigDefault policy configuration
defaultPolicy.type"rules" | "manual"Definition type of the policy"rules"
PolicyRuleConfig
defaultPolicy.permissionsPolicyRuleConfig[]Permissions of the policy
defaultPolicy.permissions[].actionYesStringAction of the rule
RuleConstraintConfig
defaultPolicy.permissions[].constraintsRuleConstraintConfig[]Constraints of the rule
defaultPolicy.permissions[].constraints[].typeYesStringType of the constraint
defaultPolicy.permissions[].constraints[].valueYesStringValue of the constraint
PolicyRuleConfig
defaultPolicy.prohibitionsPolicyRuleConfig[]Prohibitions of the policy
defaultPolicy.prohibitions[].actionYesStringAction of the rule
RuleConstraintConfig
defaultPolicy.prohibitions[].constraintsRuleConstraintConfig[]Constraints of the rule
defaultPolicy.prohibitions[].constraints[].typeYesStringType of the constraint
defaultPolicy.prohibitions[].constraints[].valueYesStringValue of the constraint
defaultPolicy.rawObjectRaw ODRL policy
RuntimeConfig
runtimeYesRuntimeConfigRuntime configuration
runtime.controlPlaneInteractions"automatic" | "semi-manual" | "manual"Mode of control plane interactions"automatic"
runtime.colorStringPrimary UI color"#3B8BF6"
runtime.lightThemeUrlStringLight theme logo URL
runtime.darkThemeUrlStringDark theme logo URL
AuditModuleConfig
auditAuditModuleConfigAudit logging configuration
audit.enabledBooleanEnable audit loggingtrue
audit.minSeverity"debug" | "info" | "warning" | "error" | "critical"Minimum severity level to log"info"
audit.logDeniedBooleanAlways log denied access attempts regardless of action typetrue
audit.logDelegatedBooleanLog delegated access attempts when enabled, while still respecting action-specific success filterstrue
audit.logMutationsBooleanLog successful mutation actions (create, update, delete, manage)true
audit.logExecuteYesBooleanLog successful execute actions
audit.logReadsYesBooleanLog successful read actions — disabled by default as reads are frequent and rarely relevant for auditing
audit.sensitiveResourcesUnknownResources that are always logged regardless of action-specific success filters["w.key","w.credential","sso.user"]
AuditHandlersConfig
audit.handlersAuditHandlersConfigHandler configuration
audit.handlers.consoleYesBooleanEnable console audit log handler
audit.handlers.databaseBooleanEnable database audit log handlertrue
audit.handlers.otlpYesBooleanEnable OTLP audit log handler
OtlpAuditHandlerConfig
audit.otlpOtlpAuditHandlerConfigOTLP audit log handler configuration
audit.otlp.urlStringOTLP HTTP logs endpoint URL"http://localhost:4318/v1/logs"
audit.otlp.headersObjectAdditional HTTP headers to include in OTLP requests
audit.otlp.timeoutMillisUnknownOTLP export timeout in milliseconds5000
audit.otlp.concurrencyLimitUnknownMaximum number of concurrent OTLP export requests1
audit.otlp.serviceNameStringService name included on OTLP log attributes"tsg-dsp-api"
audit.otlp.serviceVersionStringOptional service version included on OTLP log attributes