Skip to main content

Pinned to release v0.7.3. For the current default branch, see VC Configuration Reference.

Configuration Reference

Complete reference for all configuration parameters in the VC system.

Table of Contents

Environment Variables

These environment variables control service behavior outside of the YAML configuration file.

VariableDescriptionExample
VC_CONFIG_YAMLPath to the YAML configuration file. Each service reads this on startup.config.yaml
SSL_CERT_FILEPath to a CA certificate file that Go's crypto/x509 trusts for TLS verification. Required when services use self-signed or private CA certificates for inter-service HTTPS./pki/rootCA.crt

common (Top-level)

Shared configuration used across all services.

common

Path: .common

Constraint (mongo, sql, ha): Mongo.URI is required when SQL.Backend is 'mongo' (the default primary-store backend) or when HA.Enable is true (HA caching has no relational backend yet, so it always uses Mongo); not required for a pure relational deployment (a non-mongo SQL.Backend with HA disabled).

FieldTypeDescriptionExampleDefaultRequired
productionboolProduction mode-trueNo
logobjectLogging configuration--No
mongoobjectMongoDB configuration--No
sqlobjectRelational database configuration, used by services that support a relational storage backend as an alternative to MongoDB.--No
tracingobjectOpenTelemetry tracing configuration--No
metricsobjectOpenTelemetry metrics configuration--No
kafkaobjectKafka message broker configuration--No
secret_file_pathstringPath to a separate YAML file containing secrets; when set, secret values in config.yaml are cleared and only non-empty fields from the secrets file are applied."/etc/vc/secrets.yaml"-No
haobjectHigh-availability mode. When Enable is true, caches use MongoDB (Common.Mongo.URI) instead of in-memory storage so state is shared across instances.--No
credential_registryobjectAn optional TS11 credential metadata registry client, used as an add-on to (not a replacement for) the existing vctm_file_path/vctm_url/mddl_file_path/mddl_url per-scope configuration: disabled by default, so existing deployments are unaffected until this is explicitly enabled and at least one scope sets vct or doctype instead of a file/URL.--No
brandingobjectCustom branding configuration (logo and favicon paths)--No
credential_metadataobjectOAuth2 scope values to their credential configuration, required by apigw, issuer, and verifier Key: OAuth2 scope (e.g., "pid", "ehic", "diploma") - matches AuthorizationContext.Scope Each entry contains the VCTM reference, format, and other configuration for that credential type--No

log

Path: .common.log

FieldTypeDescriptionExampleDefaultRequired
folder_pathstringPath to the log folder"/var/log/vc"-No

mongo

Path: .common.mongo

FieldTypeDescriptionExampleDefaultRequired
uristringMongoDB connection URI. Required when Common.SQL.Backend is "mongo" (the default primary-store backend) or when Common.HA.Enable is true (pkg/cache has no relational backend yet, so HA caching always uses Mongo regardless of the primary store's backend). Enforced by a Common-level struct validation rather than a plain "required" tag here, since the requirement depends on sibling fields of Common, not of Mongo."mongodb://user:password@mongo:27017/vc"-No
tlsboolTLS for the MongoDB connection. Can also be enabled via the connection URI parameter "tls=true".-falseNo
ca_file_pathstringPath to a PEM-encoded CA certificate used to verify the MongoDB server's certificate. When empty, the system root CAs are used.--No
cert_file_pathstringPath to a PEM-encoded client certificate for mutual TLS (mTLS).--Yes (if key_file_path set)
key_file_pathstringPath to a PEM-encoded client private key for mutual TLS (mTLS).--Yes (if cert_file_path set)

sql

Path: .common.sql

Constraint (postgres, mariadb): When Backend is 'postgres', Postgres.Host and Postgres.User are required; when Backend is 'mariadb', MariaDB.Host and MariaDB.User are required. Enforced at the SQL struct level (rather than required_if tags on PostgresConfig/MariaDBConfig themselves) because 'Backend' lives on the parent SQL struct, not on those nested structs.

support a relational storage backend as an alternative to MongoDB. Backend selection is config-time only: a running service uses exactly one backend for its whole lifetime.

FieldTypeDescriptionExampleDefaultRequired
backendstringBackend selects the storage backend for services that support relational storage. "mongo" (default, current behavior) keeps existing Mongo-backed behavior unchanged; "postgres" and "mariadb" select the corresponding relational backend.-mongoNo
postgresobjectPostgres-specific connection settings, used when Backend is "postgres".--Yes (if backend is "postgres")
mariadbobjectMariaDB/MySQL-specific connection settings, used when Backend is "mariadb".--Yes (if backend is "mariadb")

postgres

Path: .common.sql.postgres

FieldTypeDescriptionExampleDefaultRequired
hoststringPostgres server hostname. Required when Common.SQL.Backend is "postgres"; enforced by a SQL-level struct validation rather than a plain "required_if" tag here, since "Backend" lives on the parent SQL struct, not on PostgresConfig, and required_if can only reference sibling fields."postgres"-No
portintPostgres server port-5432No
userstringPostgres connection user. Required when Common.SQL.Backend is "postgres" (see Host doc comment for why this isn't a required_if tag).--No
passwordstringPostgres connection password. May also be set via secrets.yaml (Common.SQL.Postgres.Password), following the same split as Mongo.URI.--No
databasestringPostgres database name"vc"vcNo
ssl_modestringPostgres SSL mode: disable, require, verify-ca, or verify-full-disableNo
ca_file_pathstringPath to a PEM-encoded CA certificate used to verify the server's certificate.--No
cert_file_pathstringPath to a PEM-encoded client certificate for mutual TLS (mTLS).--Yes (if key_file_path set)
key_file_pathstringPath to a PEM-encoded client private key for mutual TLS (mTLS).--Yes (if cert_file_path set)
max_open_connsintMaximum number of open connections to the database.-25No
max_idle_connsintMaximum number of idle connections in the pool.-5No

mariadb

Path: .common.sql.mariadb

Kept as a separate struct from PostgresConfig (rather than shared) since default port and TLS parameter semantics differ enough between the two drivers to want independent validation tags.

FieldTypeDescriptionExampleDefaultRequired
hoststringMariaDB server hostname. Required when Common.SQL.Backend is "mariadb"; enforced by a SQL-level struct validation rather than a plain "required_if" tag here, since "Backend" lives on the parent SQL struct, not on MariaDBConfig, and required_if can only reference sibling fields."mariadb"-No
portintMariaDB server port-3306No
userstringMariaDB connection user. Required when Common.SQL.Backend is "mariadb" (see Host doc comment for why this isn't a required_if tag).--No
passwordstringMariaDB connection password. May also be set via secrets.yaml (Common.SQL.MariaDB.Password), following the same split as Mongo.URI.--No
databasestringMariaDB database name"vc"vcNo
tlsboolTLS for the MariaDB connection.-falseNo
ca_file_pathstringPath to a PEM-encoded CA certificate used to verify the server's certificate.--No
cert_file_pathstringPath to a PEM-encoded client certificate for mutual TLS (mTLS).--Yes (if key_file_path set)
key_file_pathstringPath to a PEM-encoded client private key for mutual TLS (mTLS).--Yes (if cert_file_path set)
max_open_connsintMaximum number of open connections to the database.-25No
max_idle_connsintMaximum number of idle connections in the pool.-5No

tracing

Path: .common.tracing, .common.metrics

FieldTypeDescriptionExampleDefaultRequired
enableboolEnable activates OpenTelemetry tracing-falseNo
addrstringOTEL collector address"jaeger:4318"-Yes (if enabled)
timeoutint64Timeout in seconds-10No

kafka

Path: .common.kafka

FieldTypeDescriptionExampleDefaultRequired
enableboolKafka integration-falseNo
brokers[]stringList of Kafka broker addresses["kafka0:9092", "kafka1:9092"]-Yes (if enabled)
saslobjectSASL authentication for Kafka connections--No
mtlsobjectMutual TLS (mTLS) for Kafka broker connections--No

sasl

Path: .common.kafka.sasl

FieldTypeDescriptionExampleDefaultRequired
enableboolEnable activates SASL authentication-falseNo
mechanismstringSASL mechanism (PLAIN, SCRAM-SHA-256, SCRAM-SHA-512)-SCRAM-SHA-512No
usernamestringSASL username--Yes (if enabled)
passwordstringSASL password--Yes (if enabled)

mtls

Path: .common.kafka.mtls

FieldTypeDescriptionExampleDefaultRequired
enableboolMTLS for the connection-falseNo
ca_cert_pathstringPath to a CA certificate for verifying the remote peer (optional; uses system roots if empty)--No
cert_file_pathstringPath to a client certificate for mutual authentication--Yes (if enabled)
key_file_pathstringPath to the client private key--Yes (if enabled)
insecure_skip_verifyboolInsecureSkipVerify disables certificate verification (TESTING ONLY — never use in production)-falseNo

ha

Path: .common.ha

FieldTypeDescriptionExampleDefaultRequired
enableboolHA mode; when true caches are backed by MongoDB instead of in-memory storage.-falseNo
cache_database_namestringMongoDB database name used for caches.-vc_cacheNo

credential_registry

Path: .common.credential_registry

FieldTypeDescriptionExampleDefaultRequired
enableboolRegistry-backed resolution for any scope that sets vct or doctype instead of a local file/URL. Existing vctm_file_path/vctm_url/mddl_file_path/mddl_url-configured scopes are entirely unaffected either way.-falseNo
registriesarrayOrdered list of logical (independent) registries. A later entry overrides an earlier one for the same vct/doctype. Required if Enable is true.--Yes (if enabled)
refresh_intervaldurationHow long a registry's discovery index is trusted before being re-fetched. Zero means fetch once and cache forever for the lifetime of this process.-1hNo

registries entry

Path: .common.credential_registry.registries[]

FieldTypeDescriptionExampleDefaultRequired
mirrorsarraySet of endpoints serving this logical registry's content. At least one is required.--Yes

mirrors entry

Path: .common.credential_registry.registries[].mirrors[]

FieldTypeDescriptionExampleDefaultRequired
base_urlstringRegistry's origin, e.g. "https://registry.siros.org"."https://registry.siros.org"-Yes
timeoutdurationTimeout bounds each HTTP request to this registry.-10sNo

branding

Path: .common.branding

FieldTypeDescriptionExampleDefaultRequired
logo_pathstringFile path to a custom logo PNG image; when empty, the built-in SUNET logo is used--No
favicon_pathstringFile path to a custom favicon PNG image; when empty, the built-in SUNET favicon is used--No

credential_metadata entry

Path: .common.credential_metadata.<credential scope>

FieldTypeDescriptionExampleDefaultRequired
vctm_file_pathstringPath to a local VCTM JSON file. When set, apigw will publish the VCTM at /type-metadata/:scope. Used for every format except mso_mdoc.--Yes (if none of vctm_url, mddl_file_path, mddl_url, vct, doctype set)
vctm_urlstringURL where the VCTM is already published externally. When set, the VCTM is fetched from this URL at startup for internal use but NOT re-published by apigw. Used for every format except mso_mdoc.--Yes (if none of vctm_file_path, mddl_file_path, mddl_url, vct, doctype set)
vctstringVct claim value to resolve via Common.CredentialRegistry (a TS11 registry client), used only when neither VCTMFilePath nor VCTMUrl is set. Requires Common.CredentialRegistry.Enable - this field being present in a scope's config does not itself turn registry lookups on. Used for every format except mso_mdoc.--Yes (if none of vctm_file_path, vctm_url, mddl_file_path, mddl_url, doctype set)
mddl_file_pathstringPath to a local MDDL (mso_mdoc) schema JSON file, as produced by registry-cli's mddl format generator.--Yes (if none of vctm_file_path, vctm_url, mddl_url, vct, doctype set)
mddl_urlstringURL where the MDDL schema is already published externally. The mso_mdoc analogue of vctm_url.--Yes (if none of vctm_file_path, vctm_url, mddl_file_path, vct, doctype set)
doctypestringMdoc doctype value to resolve via Common.CredentialRegistry, used only when neither MDDLFilePath nor MDDLUrl is set. Requires Common.CredentialRegistry.Enable, same as VCT. Used only for mso_mdoc.--Yes (if none of vctm_file_path, vctm_url, mddl_file_path, mddl_url, vct set)
formatstringCredential format to issue"dc+sd-jwt"dc+sd-jwtNo
disclosure_policyobjectThe embedded disclosure policy for this credential type. Per ARF 3.0 §6.6.2.8 and CIR 2024/2979 Annex III. Only applicable to QEAAs and PuB-EAAs (not PIDs). When omitted, the metadata publishes policy_type "none" (no restrictions).--No
attributesobjectClaim names to their source fields and transformation rules for credential issuance--No

disclosure_policy

Path: .common.credential_metadata.<credential scope>.disclosure_policy

Per CIR 2024/2979 Annex III, three common policy types are defined.

FieldTypeDescriptionExampleDefaultRequired
policy_typestringPolicyType identifies the disclosure policy type. One of: - "none": no policy applies (default) - "authorized_relying_parties": only RPs in the allowlist may receive this attestation - "specific_root_of_trust": only RPs with access certificates from specific roots may receive this attestation-noneNo
authorized_relying_parties[]stringList of EU-wide unique Relying Party identifiers (as found in the Wallet-Relying Party Registration Certificate). Required when policy_type is "authorized_relying_parties".--Yes (if policy_type is "authorized_relying_parties")
trusted_roots[]stringList of root or intermediate certificate SHA-256 fingerprints (hex-encoded, 64 characters) from which the RP's access certificate must be derived. Required when policy_type is "specific_root_of_trust".--Yes (if policy_type is "specific_root_of_trust")

apigw (Top-level)

Configuration for the API Gateway service that handles credential issuance requests.

apigw

Path: .apigw

FieldTypeDescriptionExampleDefaultRequired
api_serverobjectHTTP API server configuration--Yes
admin_ui_enableboolThe admin web UI. When false (default), the /ui routes are not registered. This must be explicitly set to true to enable the admin interface.-falseNo
key_configobjectSigning key configuration--Yes
data_sourcesobjectCredential types to their data sources--Yes
auth_providersobjectHow users authenticate (SAML, OIDC)--No
remotesobjectNamed external API connections referenced by DataSources.ExternalAPI"ladok"-No
deliveryobjectDelivery groups credential delivery to wallets (OpenID4VCI, credential offers)--Yes
issuer_metadataobjectOpenID4VCI issuer metadata--No
public_urlstringPublic URL of this service (must be valid HTTP/HTTPS URL)"https://issuer.sunet.se"-Yes
issuer_clientobjectGRPC client config for issuer--Yes
registry_clientobjectGRPC client config for registry--Yes
identity_mapping_importobjectAutomatic import of identity mappings from JSON files at startup. When configured, APIGW reads JSON files and imports them into the identity mappings collection on first startup (skipped if data already exists).--No
trustobjectTrust evaluation configuration for OpenID4VP credential validation. When configured, credentials presented via VP are validated against a PDP.--No
federationobjectOpenID Federation entity configuration. When enabled, serves /.well-known/openid-federation as a self-signed JWT.--No
rate_limitobjectPer-endpoint rate limiting for the APIGW.--No

api_server

Path: .apigw.api_server, .issuer.api_server, .verifier.api_server, .registry.api_server

FieldTypeDescriptionExampleDefaultRequired
addrstringListen address for the HTTP server-:8080No
served_by_headerstringThe X-Served-By response header value for HA troubleshooting. Empty (default): header is not set. "hostname": uses os.Hostname(). Any other value is used as-is.--No
tlsobjectTLS--No
api_authobjectAPI Auth--No
corsobjectCORS--No
trust_proxy_tlsboolThe Secure flag on session cookies even when TLS is not enabled on this server. Use this when running behind a TLS-terminating reverse proxy.-falseNo

tls

Path: .apigw.api_server.tls, .issuer.api_server.tls, .verifier.api_server.tls, .registry.api_server.tls

FieldTypeDescriptionExampleDefaultRequired
enableboolTLS-falseNo
cert_file_pathstringPath to the TLS certificate--Yes (if enabled)
key_file_pathstringPath to the TLS private key--Yes (if enabled)

api_auth

Path: .apigw.api_server.api_auth, .issuer.api_server.api_auth, .verifier.api_server.api_auth, .registry.api_server.api_auth

Constraint (jwks, oidc): JWKS and OIDC are mutually exclusive — enable at most one.

Constraint (rules, rules_file): Authorization rules require JWKS or OIDC to be enabled.

JWKS and OIDC are mutually exclusive If neither is enabled, no authentication is applied (open access)

When Rules (and/or RulesFile) are configured, each authenticated request is checked against a SPOCP engine. A query of the form

(vc (service <SERVICE>)(method <HTTP_METHOD>)(path <REQUEST_PATH>)(subject <JWT_SUBJECT>)(authentic_source <SOURCE>)(scope <SCOPE>))

is evaluated; the request is allowed only if a matching rule exists. All six parts are required in every rule. Use * as wildcard for fields you don't want to restrict. The <SERVICE> value is supplied by the calling service at middleware registration time. When two services share endpoints, rules for one service do not grant access to the other. When no rules are configured, any valid Bearer JWT grants access.

FieldTypeDescriptionExampleDefaultRequired
jwksobjectStatic JWKS Bearer token authentication configuration When enabled, requests are validated against a manually configured JWKS URL--No
oidcobjectOIDC Bearer token authentication configuration When enabled, the JWKS endpoint is auto-discovered from the issuer's .well-known/openid-configuration and Bearer JWTs are validated locally The RP fields (client_id, redirect_uri, etc.) also enable the admin UI login flow via OIDC redirect--No
rules[]stringSPOCP S-expression authorization rules loaded into an in-process engine. All six parts (service, method, path, subject, authentic_source, scope) are mandatory in every rule — use * for wildcards. Rules apply regardless of whether JWKS or OIDC is the active auth method["(vc (service apigw)(method POST)(path /api/v1/upload)(subject alice)(authentic_source SUNET)(scope eduid))"]-No
rules_filestringOptional path to a file containing SPOCP rules (one per line) Rules from this file are loaded in addition to the inline Rules list--No

jwks

Path: .apigw.api_server.api_auth.jwks, .issuer.api_server.api_auth.jwks, .verifier.api_server.api_auth.jwks, .registry.api_server.api_auth.jwks

Constraint (jwks_url, jwks_file_path): Exactly one of jwks_url or jwks_file_path must be set when enable is true.

FieldTypeDescriptionExampleDefaultRequired
enableboolStatic JWKS Bearer token authentication-falseNo
jwks_urlstringURL of the JSON Web Key Set used to validate token signatures."https://auth.example.com/.well-known/jwks.json"-No (mutually exclusive with jwks_file_path)
jwks_file_pathstringLocal file path to a JWKS JSON file used to validate token signatures.--No (mutually exclusive with jwks_url)
issuerstringExpected "iss" claim. Tokens with a different issuer are rejected--Yes (if enabled)
audiencestringExpected "aud" claim. Tokens that do not contain this audience are rejected--Yes (if enabled)

oidc

Path: .apigw.api_server.api_auth.oidc, .issuer.api_server.api_auth.oidc, .verifier.api_server.api_auth.oidc, .registry.api_server.api_auth.oidc

It serves two purposes:

  • API auth: Bearer JWTs in Authorization headers are validated locally against the provider's JWKS (auto-discovered from IssuerURL).
  • Admin UI login: the RP fields (ClientID, RedirectURI, Scopes) enable an authorization-code redirect flow so admins log in via the OIDC provider.
FieldTypeDescriptionExampleDefaultRequired
enableboolOIDC authentication-falseNo
issuer_urlstringOIDC provider's issuer URL used for discovery and "iss" claim validation."https://auth.example.com"-Yes (if enabled)
audiencestringExpected "aud" claim. Tokens that do not contain this audience are rejected.--Yes (if enabled)
client_idstringOAuth2 client identifier registered with the OIDC provider.--Yes (if enabled)
client_secretstringOAuth2 client secret. May be empty for public clients.--No
redirect_uristringCallback URL for the admin UI OIDC login flow."https://apigw.example.com/ui/callback"-Yes (if enabled)
scopes[]stringOAuth2/OIDC scopes to request (default: ["openid"]).--No

cors

Path: .apigw.api_server.cors, .issuer.api_server.cors, .verifier.api_server.cors, .registry.api_server.cors

FieldTypeDescriptionExampleDefaultRequired
allowed_origins[]stringList of allowed CORS origins["https://wallet.sunet.se", "https://app.sunet.se"][]No

key_config

Path: .apigw.key_config, .issuer.key_config, .verifier.key_config, .registry.token_status_lists.key_config

Supports both file-based and HSM-based keys with explicit control.

FieldTypeDescriptionExampleDefaultRequired
private_key_pathstringFile-based configuration--Yes (if pkcs11 not set)
chain_pathstringPath to certificate chain (optional)--No
pkcs11objectHSM-based configuration--Yes (if private_key_path not set)
sourceobjectSource selection (determines which config to use) If empty, tries in order: File (if FilePath set), then HSM (if HSM set)--No
enable_fileboolFile-based key loading (default: true if FilePath set)--No
enable_hsmboolHSM-based key loading (default: true if HSM set)--No
priorityarrayFallback order when both are enabled If nil, uses Source field or auto-detects based on what's configured["hsm", "file"]-No

pkcs11

Path: .apigw.key_config.pkcs11, .issuer.key_config.pkcs11, .verifier.key_config.pkcs11, .registry.token_status_lists.key_config.pkcs11

FieldTypeDescriptionExampleDefaultRequired
module_pathstringPath to the PKCS#11 library"/usr/lib/softhsm/libsofthsm2.so"-No
slot_iduintHSM slot ID0-No
pinstringUser PIN for the slot"1234"-No
key_labelstringLabel of the key to use"my-signing-key"-No
key_idstringIdentifier for the JWT kid header"key-1"-No

data_sources

Path: .apigw.data_sources

Each key under a data source is a credential type.

FieldTypeDescriptionExampleDefaultRequired
datastoreobjectCredential types backed by a pre-loaded datastore (e.g. MongoDB)--No
assertionobjectCredential types backed by authentication assertions (SAML attributes or OIDC claims)--No
external_apiobjectCredential types backed by an external API Each credential references a named remote defined in APIGW.Remotes--No

datastore

Path: .apigw.data_sources.datastore

FieldTypeDescriptionExampleDefaultRequired
scopesobjectCredential scope names to their datastore configuration--No
importobjectAutomatic data import from JSON files at startup. When configured, APIGW reads JSON files and imports them into the datastore on first startup (skipped if data already exists).--No

scopes entry

Path: .apigw.data_sources.datastore.scopes.<credential scope>

FieldTypeDescriptionExampleDefaultRequired
auth_providerstringAuth provider for this credential type (openid4vp, saml, or oidc)--Yes
auth_claims[]stringThe normalized claim names used for datastore identity lookup when auth_provider is saml or oidc. Not used for openid4vp (use AuthScopes instead). These names must match the BSON field names under "identities." in the datastore. Use attribute_mappings (in auth_providers) to normalize provider-specific attribute names (e.g. SAML urn:oid:2.5.4.42, eIDAS date_of_birth) to these canonical names. Available identity fields: given_name, family_name, birth_date, birth_place, authentic_source_person_id, personal_administrative_number.[given_name, family_name, birth_date]-No
auth_scopesobjectCredential scope keys to their per-scope authentication config. Used only for openid4vp: the wallet must present a credential matching any one of the listed scopes (OR logic). Each entry specifies which claims to extract from that particular credential type.--No

auth_scopes entry

Path: .apigw.data_sources.datastore.scopes.<credential scope>.auth_scopes.<key>

Each entry represents one acceptable credential type the wallet can present.

FieldTypeDescriptionExampleDefaultRequired
auth_claims[]stringThe identity claims to extract from this credential type.[given_name, family_name, birth_date]-Yes

import

Path: .apigw.data_sources.datastore.import

FieldTypeDescriptionExampleDefaultRequired
file_paths[]stringJSON files to import into the datastore. Each JSON file should contain a map of person IDs to CompleteDocument objects. Import is skipped if the datastore already contains data.["./bootstrapping/pid.json", "./bootstrapping/ehic.json"]-Yes
users[]stringUsers limits which person IDs to import. If empty, all persons are imported.["100", "102"]-No

assertion

Path: .apigw.data_sources.assertion

FieldTypeDescriptionExampleDefaultRequired
scopesobjectCredential scope names to their assertion configuration--No

scopes entry

Path: .apigw.data_sources.assertion.scopes.<credential scope>

The data comes directly from the SAML attributes or OIDC claims.

FieldTypeDescriptionExampleDefaultRequired
auth_providerstringAuth provider for this credential type (saml or oidc)--Yes

external_api

Path: .apigw.data_sources.external_api

FieldTypeDescriptionExampleDefaultRequired
scopesobjectCredential scope names to their external API configuration--No

scopes entry

Path: .apigw.data_sources.external_api.scopes.<credential scope>

FieldTypeDescriptionExampleDefaultRequired
remotestringName of a remote defined in Remotes--Yes
auth_providerstringAuth provider to identify the user (saml or oidc)--Yes
attribute_mappingobjectHow to map API response data to credential claims--No

attribute_mapping entry

Path: .apigw.data_sources.external_api.scopes.<credential scope>.attribute_mapping.<attribute>, .apigw.auth_providers.saml.attribute_mapping.<attribute>, .apigw.auth_providers.oidc.attribute_mapping.<attribute>

Generic across protocols (SAML, OIDC, etc.) - uses protocol-specific identifiers as keys

FieldTypeDescriptionExampleDefaultRequired
claimstringTarget claim name (supports dot-notation for nesting)"identity.given_name"-Yes
requiredboolRequired indicates if this attribute must be present in the assertion/response-falseNo
transformstringOptional transformation to apply Supported: "lowercase", "uppercase", "trim", "country_alpha2", "country_alpha3"--No
defaultstringOptional default value if attribute is missing--No
as_arrayboolAsArray wraps a scalar value in a single-element array before setting the claim. No-op when the value is already a slice (e.g. multi-valued OIDC claim).--No

auth_providers

Path: .apigw.auth_providers

FieldTypeDescriptionExampleDefaultRequired
samlobjectThe SAML SP auth provider--No
oidcobjectThe OIDC RP auth provider--No

saml

Path: .apigw.auth_providers.saml

Constraint (mdq_server, static_idp_metadata): Exactly one of mdq_server or static_idp_metadata must be set when enable is true. Mutual exclusivity is enforced by field tags.

FieldTypeDescriptionExampleDefaultRequired
enableboolSAML support (default: false)-falseNo
entity_idstringSAML SP entity identifier (typically the metadata URL)"https://issuer.sunet.se/saml/metadata"-Yes (if enabled)
metadata_urlstringPublic URL where SP metadata is served (optional, auto-generated if empty)--No
mdq_serverstringBase URL for MDQ (Metadata Query Protocol) server (must end with /)"https://md.sunet.se/entities/"-No (mutually exclusive with static_idp_metadata)
static_idp_metadataobjectA single static IdP as alternative to MDQ--No (mutually exclusive with mdq_server)
certificate_pathstringPath to X.509 certificate for SAML signing/encryption TODO(pki): Migrate to pki.KeyConfig for consistency with other services and to enable HSM-backed SAML signing keys in the future.--Yes (if enabled)
private_key_pathstringPath to private key for SAML signing/encryption TODO(pki): See CertificatePath TODO — both fields would be replaced by a single KeyConfig.--Yes (if enabled)
acs_endpointstringAssertion Consumer Service URL where IdP sends SAML responses"https://issuer.sunet.se/saml/acs"-Yes (if enabled)
session_durationintMaximum time in seconds an in-flight SAML authentication flow (AuthnRequest → Response) may remain active before it expires-300No
attribute_mappingobjectAttributeMapping normalizes provider-specific attribute names (e.g. SAML OIDs) to canonical claim names. Applied to ALL attributes in the assertion. Which normalized attributes are used depends on the data source: - assertion: VCTM determines which go into the credential - datastore: auth_claims determines which are used for DB identity lookup--Yes (if enabled)
metadata_signing_cert_pathstringPath to the X.509 certificate used to verify metadata signatures. When set, all fetched metadata (MDQ and static) must carry a valid XML signature from this certificate.--No
allow_unsigned_metadataboolAllowUnsignedMetadata permits MDQ/URL metadata without signature verification. This is INSECURE (MITM → fake IdP) and should only be used in development. When false (default), MDQ and URL metadata sources require MetadataSigningCertPath. Local metadata files are allowed unsigned regardless (with a startup warning).-falseNo
metadata_cache_ttlintMetadataCacheTTL in seconds (default: 3600) - how long to cache IdP metadata from MDQ--No

static_idp_metadata

Path: .apigw.auth_providers.saml.static_idp_metadata

FieldTypeDescriptionExampleDefaultRequired
entity_idstringIdP entity identifier--Yes
metadata_pathstringFile path to IdP metadata XML--Yes (if metadata_url not set; mutually exclusive)
metadata_urlstringHTTP(S) URL to fetch IdP metadata from (mutually exclusive with MetadataPath)--No

oidc

Path: .apigw.auth_providers.oidc

Constraint (scopes): The 'openid' scope is mandatory when OIDC RP is enabled.

FieldTypeDescriptionExampleDefaultRequired
enableboolOIDC RP support (default: false)-falseNo
registrationobjectHow the client obtains credentials from the OIDC Provider. Exactly one of preconfigured or dynamic must be set: - preconfigured: pre-registered client_id and client_secret - dynamic: RFC 7591 dynamic client registration (credentials obtained at startup)--Yes (if enabled)
redirect_uristringCallback URL where the OIDC Provider sends the authorization response"https://issuer.sunet.se/oidcrp/callback"-Yes (if enabled)
issuer_urlstringOIDC Provider's issuer URL for discovery Used for .well-known/openid-configuration discovery"https://accounts.google.com"-Yes (if enabled)
scopes[]stringOAuth2/OIDC scopes to request-["openid", "profile", "email"]No
session_durationintMaximum time in seconds an in-flight OIDC authorization flow (state, nonce, PKCE verifier) may remain active before it expires-300No
client_namestringHuman-readable name for the OIDC client, shown during dynamic registration or consent--No
client_uristringURL to the client's homepage, used for display during consent--No
logo_uristringURL to the client's logo image, shown during consent screens--No
contacts[]stringList of email addresses for responsible parties of this client--No
tos_uristringURL to the client's Terms of Service document--No
policy_uristringURL to the client's Privacy Policy document--No
attribute_mappingobjectAttributeMapping normalizes OIDC claim names to canonical claim names. Optional: when omitted, OIDC claims pass through as-is (standard names already match). Which normalized attributes are used depends on the data source: - assertion: VCTM determines which go into the credential - datastore: auth_claims determines which are used for DB identity lookup--No

registration

Path: .apigw.auth_providers.oidc.registration

FieldTypeDescriptionExampleDefaultRequired
preconfiguredobjectPreconfigured uses pre-registered client credentials. Set this when the client is already registered with the OIDC Provider.--Yes (if dynamic not set; mutually exclusive)
dynamicobjectDynamic uses RFC 7591 dynamic client registration. Set this when the client should register itself at startup.--Yes (if preconfigured not set; mutually exclusive)

preconfigured

Path: .apigw.auth_providers.oidc.registration.preconfigured

FieldTypeDescriptionExampleDefaultRequired
enableboolEnable activates preconfigured client credentials--No
client_idstringOIDC client identifier--Yes (if enabled)
client_secretstringOIDC client secret--Yes (if enabled)

dynamic

Path: .apigw.auth_providers.oidc.registration.dynamic

When set, client credentials are obtained automatically at startup and persisted in the database.

FieldTypeDescriptionExampleDefaultRequired
enableboolEnable activates dynamic client registration--No
initial_access_tokenstringBearer token for registration Required by some OIDC Providers (e.g., Keycloak)--Yes (if enabled)

remotes entry

Path: .apigw.remotes.<remote name>

FieldTypeDescriptionExampleDefaultRequired
typestring (eduapi|ooapi)API protocol type--Yes
base_urlstringBase URL of the API endpoint"https://api.ladok.se/eduapi"-Yes
token_urlstringOAuth 2.0 token endpoint for Client Credentials Grant"https://api.ladok.se/oauth2/token"-Yes
client_idstringOAuth 2.0 client identifier--Yes
client_secretstringOAuth 2.0 client secret--Yes
scopes[]stringOAuth 2.0 scopes to request--No
timeoutdurationHTTP client timeout-10sNo

delivery

Path: .apigw.delivery

FieldTypeDescriptionExampleDefaultRequired
openid4vciobjectThe OpenID4VCI Authorization Server for wallet credential issuance--Yes
credential_offersobjectCredential offer wallet configurations--Yes

openid4vci

Path: .apigw.delivery.openid4vci

FieldTypeDescriptionExampleDefaultRequired
token_endpointstringOAuth2 token endpoint URL"https://verifier.sunet.se/token"-Yes
clientsobjectOAuth2 client configurations--Yes
allow_unverified_client_assertionboolAccepting client_assertion (private_key_jwt) WITHOUT signature verification. This is INSECURE and only intended for conformance testing environments. When false (default), client_assertion is rejected. TODO(security): Remove this flag once full RFC 7523 verification is implemented.-falseNo
grant_types[]stringList of grant types this issuer supports. Supported values: authorization_code, urn:ietf:params:oauth:grant-type:pre-authorized_code, refresh_token-["authorization_code", "urn:ietf:params:oauth:grant-type:pre-authorized_code"]No
refresh_token_durationintRefresh token duration in seconds. Only applicable when grant_types includes "refresh_token".-86400No

clients entry

Path: .apigw.delivery.openid4vci.clients.<client id>, .verifier.inbound.openid4vp.clients.<client id>

FieldTypeDescriptionExampleDefaultRequired
typestringClient type per RFC 6749 Section 2.1 ("public" or "confidential"). Defaults to "public" since registered clients are wallets (native/web apps) that cannot securely store credentials and rely on PKCE instead.-publicNo
redirect_uri[]stringList of allowed redirect URIs for the client. Accepts either a single string or an array of strings in YAML/JSON."https://example.com/callback"-Yes
scopes[]stringList of OAuth2 scopes allowed for the client--Yes
jwks_uristringURL to the client's JWKS for verifying client_assertion signatures (RFC 7523). Required for confidential clients using private_key_jwt authentication.--Yes (if type is "confidential")

credential_offers

Path: .apigw.delivery.credential_offers

FieldTypeDescriptionExampleDefaultRequired
issuer_urlstringIssuer URL for credential offers--Yes
walletsobjectWallet redirect configurations--Yes

wallets entry

Path: .apigw.delivery.credential_offers.wallets.<wallet name>

FieldTypeDescriptionExampleDefaultRequired
labelstringDisplay label for the wallet--Yes
redirect_uristringWallet redirect URI"eudi-wallet://credential-offer"-Yes

issuer_metadata

Path: .apigw.issuer_metadata

FieldTypeDescriptionExampleDefaultRequired
authorization_servers[]stringThe authorization server URLs--No
deferred_credential_endpointstringDeferred credential endpoint--No
notification_endpointstringNotification endpoint--No
cryptographic_binding_methods_supported[]stringThe supported binding methods--No
credential_signing_alg_values_supported[]stringThe supported signing algorithms--No
proof_signing_alg_values_supported[]stringThe supported proof algorithms--No
credential_response_encryptionobjectResponse encryption configuration--No
batch_credential_issuanceobjectBatch issuance configuration--No
displayarrayDisplay metadata--No
mdoc_iacas_uristringURL where IACA certificates are published for mDOC verification. When configured, this is included in .well-known/openid-credential-issuer metadata so verifiers can dynamically discover trust anchors for ISO 18013-5 credentials.--No

credential_response_encryption

Path: .apigw.issuer_metadata.credential_response_encryption

FieldTypeDescriptionExampleDefaultRequired
alg_values_supported[]stringAlgValuesSupported: REQUIRED. Array containing a list of the JWE [RFC7516] encryption algorithms (alg values) [RFC7518] supported by the Credential and Batch Credential Endpoint to encode the Credential or Batch Credential Response in a JWT [RFC7519].--Yes
enc_values_supported[]stringEncValuesSupported: REQUIRED. Array containing a list of the JWE [RFC7516] encryption algorithms (enc values) [RFC7518] supported by the Credential and Batch Credential Endpoint to encode the Credential or Batch Credential Response in a JWT [RFC7519].--Yes
encryption_requiredboolEncryptionRequired: REQUIRED. Boolean value specifying whether the Credential Issuer requires the additional encryption on top of TLS for the Credential Response. If the value is true, the Credential Issuer requires encryption for every Credential Response and therefore the Wallet MUST provide encryption keys in the Credential Request. If the value is false, the Wallet MAY chose whether it provides encryption keys or not.--No

batch_credential_issuance

Path: .apigw.issuer_metadata.batch_credential_issuance

FieldTypeDescriptionExampleDefaultRequired
batch_sizeintBatchSize: REQUIRED. Integer value specifying the maximum array size for the proofs parameter in a Credential Request.--Yes

display entry

Path: .apigw.issuer_metadata.display[]

FieldTypeDescriptionExampleDefaultRequired
namestringName: OPTIONAL. String value of a display name for the Credential Issuer.--No
localestringLocale: OPTIONAL. String value that identifies the language of this object represented as a language tag taken from values defined in BCP47 [RFC5646]. There MUST be only one object for each language identifier.--No
logoobjectLogo: OPTIONAL. Object with information about the logo of the Credential Issuer. Below is a non-exhaustive list of parameters that MAY be included:--No

Path: .apigw.issuer_metadata.display[].logo

FieldTypeDescriptionExampleDefaultRequired
uristringURI: REQUIRED. String value that contains a URI where the Wallet can obtain the logo of the Credential Issuer. The Wallet needs to determine the scheme, since the URI value could use the https: scheme, the data: scheme, etc.--Yes
alt_textstringAltText: OPTIONAL. String value of the alternative text for the logo image.--No

issuer_client

Path: .apigw.issuer_client, .apigw.registry_client, .issuer.registry_client

FieldTypeDescriptionExampleDefaultRequired
addrstringGRPC server address"issuer:8090"-Yes
tlsboolTLS-falseNo
cert_file_pathstringClient certificate for mTLS--No
key_file_pathstringClient private key for mTLS--No
ca_file_pathstringCA certificate to verify the server--No
server_namestringServer name for TLS verification (optional)--No

identity_mapping_import

Path: .apigw.identity_mapping_import

FieldTypeDescriptionExampleDefaultRequired
file_paths[]stringJSON files containing identity mappings to import. Each JSON file should contain a map of person IDs to arrays of IdentityMapping objects. Import is skipped if the identity mappings collection already contains data.["./bootstrapping/identity_mappings.json"]-Yes
users[]stringUsers limits which person IDs to import. If empty, all persons are imported.["100", "102"]-No

trust

Path: .apigw.trust, .verifier.trust

This is used for validating W3C VC Data Integrity proofs and other trust-related operations.

Trust evaluation operates in one of two modes:

  • When PDPURL is configured: "default deny" mode - all trust decisions go through the PDP
  • When PDPURL is empty: "allow all" mode - keys are resolved but always considered trusted
FieldTypeDescriptionExampleDefaultRequired
pdp_urlstringURL of the AuthZEN PDP (Policy Decision Point) service for trust evaluation. When set, operates in "default deny" mode - trust decisions require PDP approval. When empty, operates in "allow all" mode - resolved keys are always considered trusted."https://trust.sunet.se/pdp"-No
local_did_methods[]stringWhich DID methods can be resolved locally without go-trust. Self-contained methods like "did:key" and "did:jwk" are always resolved locally.-["did:key", "did:jwk"]No
trust_policiesobjectPer-role trust evaluation policies. The key is the role (e.g., "issuer", "verifier") and the value contains policy settings.--No
allowed_signature_algorithms[]stringAllowedSignatureAlgorithms restricts which JWT signature algorithms are accepted. If empty, defaults to a secure set: ES256, ES384, ES512, RS256, RS384, RS512, PS256, PS384, PS512, EdDSA. The "none" algorithm is NEVER allowed regardless of configuration.["ES256", "ES384", "ES512", "EdDSA"]-No
wallet_attestationobjectWallet attestation-based client authentication. This is a trust-evaluation mechanism (delegates to the PDP above), so it lives here rather than under delivery.openid4vci.--No

trust_policies entry

Path: .apigw.trust.trust_policies.<role>, .verifier.trust.trust_policies.<role>

FieldTypeDescriptionExampleDefaultRequired
trust_frameworks[]stringThe accepted trust frameworks for this role.["did:web", "did:ebsi", "etsi-tl", "openid-federation", "x509"]-No
trust_anchors[]stringTrusted root entities for this role. Format depends on the trust framework (e.g., DID for did:web, federation entity for OpenID Fed).--No
require_revocation_checkboolRequireRevocationCheck enforces revocation status checking for this role. Default: false-falseNo

wallet_attestation

Path: .apigw.trust.wallet_attestation, .verifier.trust.wallet_attestation

FieldTypeDescriptionExampleDefaultRequired
enabledboolWallet attestation-based authentication. When true and PDPURL is configured, wallets can authenticate using a provider-signed attestation JWT instead of pre-registration in Clients. The PDP validates the wallet provider against configured trust lists/federation. PKCE remains mandatory as the primary code-binding mechanism.-falseNo
policyobjectSPOCP-based authorization for wallet attestation. When configured, after the PDP validates the wallet provider, the SPOCP engine checks whether the attestation tier (attestation_source) is authorized for the requested scope. When empty, all trusted wallets are authorized (default open).--No
modestringMode restricts which WIA trust model this deployment accepts, matching the same "etsi"/"ietf" terminology used by go-wallet-backend's WIAConfig.Mode: - "etsi": require x5c (EC TS03 v1.5.2 / ETSI TS 119 472-3 model, identity verified against the Trusted List for Wallet Providers). A WIA without x5c is rejected before signature verification. - "ietf": require iss + no x5c (the plain IETF draft-ietf-oauth-attestation-based-client-auth format, resolved via JWKS discovery — no ARF/ETSI counterpart). A WIA with x5c is rejected before signature verification. - "" (default): accept either format, as determined by whether the WIA carries an x5c header or an iss claim — preserves pre-Mode behavior for deployments that haven't opted into pinning one trust model. Any other value is treated the same as "" (a warning is logged, not a startup failure — this package has no config.Validate() convention to hard-fail against). Pinning this matters beyond documentation: without it, an operator expecting only ARF-conformant ("etsi") wallets would still silently accept an iss/JWKS-based ("ietf") WIA from a misconfigured or malicious wallet, trusting a JWKS discovery chain instead of the Trusted List for Wallet Providers PKI anchor.--No

policy

Path: .apigw.trust.wallet_attestation.policy, .verifier.trust.wallet_attestation.policy

Each rule is an S-expression of the form:

(wallet (attestation_source <tier>)(scope <scope>)(issuer <provider>))

Use * as wildcard. When no rules are configured, any trusted wallet is authorized. Example rules:

(wallet (attestation_source ios_app_attest)(scope pid)(issuer *)) — allow iOS Tier 4+ for PID (wallet (attestation_source android_play_integrity)(scope pid)(issuer *)) — allow Android Tier 4+ for PID (wallet (attestation_source *)(scope ehic)(issuer *)) — allow any tier for EHIC

FieldTypeDescriptionExampleDefaultRequired
rules[]stringInline SPOCP rules.--No
rules_filestringPath to a file containing SPOCP rules (one per line, # comments).--No

federation

Path: .apigw.federation, .verifier.federation

FieldTypeDescriptionExampleDefaultRequired
enabledboolThe federation entity configuration endpoint.-falseNo
entity_idstringEntity identifier (defaults to PublicURL if empty).--No
authority_hints[]stringSuperior authority entity identifiers.--No
organization_namestringHuman-readable organization name.--No
logo_uristringOrganization logo URL.--No
trust_marksarrayTrustMarks contains pre-issued trust mark JWTs.--No
ttlint64Validity period of the entity configuration in seconds. Default: 86400 (24 hours).-86400No

trust_marks entry

Path: .apigw.federation.trust_marks[], .verifier.federation.trust_marks[]

FieldTypeDescriptionExampleDefaultRequired
idstringTrust mark identifier.--Yes
jwtstringTrust mark JWT string.--Yes

rate_limit

Path: .apigw.rate_limit

FieldTypeDescriptionExampleDefaultRequired
token_requests_per_minuteintMaximum token endpoint requests per minute per IP. Default: 20-20No
credential_requests_per_minuteintMaximum credential endpoint requests per minute per IP. Default: 30-30No
datastore_requests_per_minuteintMaximum datastore endpoint requests per minute per IP. Default: 60-60No

issuer (Top-level)

Configuration for the Issuer service that signs and issues verifiable credentials.

issuer

Path: .issuer

FieldTypeDescriptionExampleDefaultRequired
api_serverobjectHTTP API server configuration--Yes
grpc_serverobjectGRPC server configuration--Yes
key_configobjectSigning key configuration--Yes
jwt_attributeobjectJWT credential attribute configuration--Yes
issuer_urlstringIssuer identifier URL"https://issuer.sunet.se"-Yes
registry_clientobjectRegistry gRPC client config--No
mdocobjectMDL/mdoc configuration--No
audit_logobjectAudit log configuration--No
sign_metadata_rate_limitobjectThe rate limiter for the SignMetadata gRPC endpoint. In HA setups each APIGW node refreshes two documents (VCI+OAuth2), so the defaults should accommodate the expected cluster size. Default: 2 req/s, burst 20.--No
pseudonym_seedboolPseudonymSeed, if true, makes the issuer attach a random seed as the pseudonym_seed claim.--No

grpc_server

Path: .issuer.grpc_server, .registry.grpc_server

FieldTypeDescriptionExampleDefaultRequired
addrstringGRPC server listen address-:8090No
tlsobjectMTLS configuration--No

tls

Path: .issuer.grpc_server.tls, .registry.grpc_server.tls

FieldTypeDescriptionExampleDefaultRequired
enableboolEnable-falseNo
cert_file_pathstringServer certificate-/pki/grpc_server.crtNo
key_file_pathstringServer private key-/pki/grpc_server.keyNo
client_ca_pathstringCA to verify client certificates (for mTLS)-/pki/client_ca.crtNo
allowed_client_fingerprintsobjectSHA256 fingerprint -> friendly namea1b2c3...: issuer-prod-No
allowed_client_dnsobjectFriendly name -> Certificate Subject DNapigw-prod: CN=apigw,O=SUNET-No

jwt_attribute

Path: .issuer.jwt_attribute

In a later state this should be placed under authentic source in order to issue credentials based on that configuration.

FieldTypeDescriptionExampleDefaultRequired
issuerstringIssuer of the tokenhttps://issuer.sunet.se-Yes
static_hoststringStatic host of the issuer, expose static files, like pictures.--No
enable_not_beforeboolThe time not before which the token is valid-falseNo
valid_durationint64Valid duration of the token in seconds-3600No
verifiable_credential_typestringVerifiableCredentialType URLhttps://credential.sunet.se/identity_credential-Yes
statusstringStatus status of the Verifiable Credential--No
kidstringKid key id of the signing key--No

mdoc

Path: .issuer.mdoc

FieldTypeDescriptionExampleDefaultRequired
certificate_chain_pathstringPath to the PEM certificate chain TODO(pki): Consider folding into pki.KeyConfig.ChainPath to unify certificate chain loading with the standard key material configuration pattern.--Yes
default_validitydurationDefault credential validity (default: 365 days)-8760hNo
digest_algorithmstringDigest algorithm: "SHA-256", "SHA-384", or "SHA-512"-SHA-256No

audit_log

Path: .issuer.audit_log

FieldTypeDescriptionExampleDefaultRequired
enableboolAudit logging-falseNo
destinations[]stringList of log destinations (console/stdout, file path, or HTTP URL)["stdout", "/var/log/audit.log", "https://audit.sunet.se/webhook"]-Yes (if enabled)
file_sync_intervaldurationFsync behavior for file destinations. 0 = fsync after every write (strict durability, lower throughput). >0 = periodic batched fsync at the given interval (better throughput, bounded data-loss window). Has no effect on console or webhook destinations.-5sNo

sign_metadata_rate_limit

Path: .issuer.sign_metadata_rate_limit

FieldTypeDescriptionExampleDefaultRequired
requests_per_secondfloat64Sustained rate limit in requests per second. Default: 2-2No
burstintMaximum number of requests allowed in a single burst. Default: 20-20No

verifier (Top-level)

Configuration for the Verifier service that verifies credentials and acts as an OIDC Provider.

verifier

Path: .verifier

FieldTypeDescriptionExampleDefaultRequired
api_serverobjectHTTP API server configuration--Yes
public_urlstringPublic URL of this service (must be valid HTTP/HTTPS URL)"https://verifier.sunet.se"-Yes
key_configobjectSigning key configuration--Yes
client_id_schemestringClientIDScheme determines how the verifier identifies itself to wallets. Supported values: "x509_san_dns" (default), "did". When "did", the DID field must be set and /.well-known/did.json is served.-x509_san_dnsNo
didstringVerifier's DID identity."did:web:verifier.example.com"-Yes (if client_id_scheme is "did")
preferred_vp_formatsobjectInformational VP formats and algorithms supported by wallets--No
supported_walletsobjectSupported wallet configurations--No
inboundobjectInbound groups inbound credential verification--No
outboundobjectOutbound groups outbound identity assertion--No
digital_credentialsobjectW3C Digital Credentials API configuration--No
authorization_page_cssobjectAuthorization page styling configuration--No
credential_displayobjectCredential display settings--No
trustobjectTrust evaluation configuration--No
federationobjectOpenID Federation entity configuration. When enabled, serves /.well-known/openid-federation as a self-signed JWT.--No
presetsobjectPredefined verification request presets shown in the UI. The map key is the human-readable label. Each preset maps credential_metadata scopes to optional claim overrides. A nil scope value requests all VCTM claims; use claims/exclude_claims to narrow."PID":{"pid":null},"PID + EHIC":{"pid":null,"ehic":null}-No
combined_presentationobjectCombined presentation verification (ARF 3.0 §6.6.3.10). When multiple credentials are presented, this verifies they belong to the same holder.--No
revocationobjectCredential revocation checking at presentation time (ARF 3.0 §6.6.3.7). When enabled, the Verifier checks Token Status List references in presented credentials.--No
zk_circuitsobjectThe zk-circuits catalog service used to resolve "mso_mdoc_zk" (Longfellow ZK/PPID) proof circuits for native verification. Only consulted by builds with the "zknative" Go build tag (see pkg/mdoc/zk_native_cgo.go) - ignored by the default build.--No

preferred_vp_formats

Path: .verifier.preferred_vp_formats

Used in client_metadata and Wallet metadata to indicate supported formats and algorithms.

FieldTypeDescriptionExampleDefaultRequired
ldp_vcobjectConfiguration for W3C VC Data Integrity format (ldp_vc)--No
jwt_vc_jsonobjectConfiguration for JWT-based W3C VC format (jwt_vc_json)--No
dc+sd-jwtobjectConfiguration for SD-JWT VC format (dc+sd-jwt)--No
mso_mdocobjectConfiguration for ISO mdoc format (mso_mdoc)--No

ldp_vc

Path: .verifier.preferred_vp_formats.ldp_vc

FieldTypeDescriptionExampleDefaultRequired
proof_type_values[]stringNon-empty array containing identifiers of proof types supported. If present, the proof type of the presented VC/VP MUST match one of the array values.["DataIntegrityProof", "Ed25519Signature2020"]-No
cryptosuite_values[]stringNon-empty array containing identifiers of crypto suites supported. Used when one of the algorithms in ProofTypeValues supports multiple crypto suites.["ecdsa-rdfc-2019", "ecdsa-sd-2023", "eddsa-rdfc-2022", "bbs-2023"]-No

jwt_vc_json

Path: .verifier.preferred_vp_formats.jwt_vc_json

FieldTypeDescriptionExampleDefaultRequired
alg_values[]stringNon-empty array containing identifiers of cryptographic algorithms supported. If present, the alg JOSE header of the presented VC/VP MUST match one of the array values.--No

dc+sd-jwt

Path: .verifier.preferred_vp_formats.dc+sd-jwt

FieldTypeDescriptionExampleDefaultRequired
sd-jwt_alg_values[]stringNon-empty array containing cryptographic algorithm identifiers supported for the Issuer-signed JWT of an SD-JWT.--No
kb-jwt_alg_values[]stringNon-empty array containing cryptographic algorithm identifiers supported for a Key Binding JWT (KB-JWT).--No

mso_mdoc

Path: .verifier.preferred_vp_formats.mso_mdoc

FieldTypeDescriptionExampleDefaultRequired
issuerauth_alg_values[]intNon-empty array containing cryptographic algorithm identifiers supported for IssuerAuth COSE signatures.--No
deviceauth_alg_values[]intNon-empty array containing cryptographic algorithm identifiers supported for DeviceAuth COSE signatures or MACs.--No

inbound

Path: .verifier.inbound

FieldTypeDescriptionExampleDefaultRequired
openid4vpobjectOpenID4VP configuration for accepting wallet presentations--Yes

openid4vp

Path: .verifier.inbound.openid4vp

FieldTypeDescriptionExampleDefaultRequired
presentation_timeoutintPresentation timeout in seconds-300No
supported_credentialsarraySupported credential configurations--Yes
presentation_requests_dirstringOptional directory with presentation request templates--No
token_endpointstringOAuth2 token endpoint URL used for VP token exchange"https://verifier.sunet.se/token"-Yes
clientsobjectOAuth2 client configurations for RP interactions--Yes

supported_credentials entry

Path: .verifier.inbound.openid4vp.supported_credentials[]

FieldTypeDescriptionExampleDefaultRequired
vctstringVerifiable credential type"urn:eudi:pid:1"-Yes
scopes[]stringOIDC scopes that grant access to this credential--Yes

outbound

Path: .verifier.outbound

FieldTypeDescriptionExampleDefaultRequired
oidc_providerobjectOIDC Provider configuration for asserting verified identity to downstream RPs--No

oidc_provider

Path: .verifier.outbound.oidc_provider

This configures how the verifier issues ID tokens and access tokens to relying parties. Note: This is NOT related to verifiable credential issuance (see IssuerConfig for VC issuance). The signing key is shared from the parent Verifier.KeyConfig.

FieldTypeDescriptionExampleDefaultRequired
issuerstringOIDC Provider identifier that appears in ID tokens and discovery metadata. This identifies the verifier as an OpenID Provider. Must match the 'iss' claim in all issued ID tokens."https://verifier.sunet.se"-Yes
session_durationintSession duration in seconds-3600No
code_durationintAuthorization code duration in seconds-300No
access_token_durationintAccess token duration in seconds-3600No
id_token_durationintID token duration in seconds-3600No
refresh_token_durationintRefresh token duration in seconds-86400No
subject_typestringSubject type: "public" or "pairwise"--Yes
subject_saltstringSalt for pairwise subject generation--Yes
enable_userinfoboolWhether the verifier-OP advertises a userinfo_endpoint in its discovery metadata and issues JWT access tokens (RFC 9068 at+jwt). When true (default), the OP advertises userinfo_endpoint in discovery and returns an access token alongside the ID token. The userinfo endpoint is stateless: it validates the JWT signature and returns the embedded claims. When false, only ID tokens are returned — no access_token or userinfo endpoint.-trueNo
static_clientsarrayList of pre-configured OIDC clients These clients are checked in addition to dynamically registered clients--No

static_clients entry

Path: .verifier.outbound.oidc_provider.static_clients[]

Static clients are configured in YAML and do not require dynamic registration. These clients are checked in addition to dynamically registered clients stored in the database.

FieldTypeDescriptionExampleDefaultRequired
client_idstringUnique identifier for the client--Yes
client_secretstringClient secret for authentication. Can be defined in the secrets file under verifier.oidc_op.static_clients as a map of client_id to client_secret.--Yes (unless token_endpoint_auth_method is "none")
redirect_uris[]stringList of allowed redirect URIs for this client--Yes
allowed_scopes[]stringList of scopes this client is allowed to request. If empty, defaults to standard OIDC scopes (openid, profile, email, address, phone).--No
token_endpoint_auth_methodstringAuthentication method for the token endpoint. Supported values: client_secret_basic, client_secret_post, none (public client) Default: "client_secret_basic"-client_secret_basicNo
grant_types[]stringList of allowed grant types. Supported values: authorization_code, refresh_token Default: ["authorization_code"]-["authorization_code"]No
response_types[]stringList of allowed response types. Supported values: code Default: ["code"]-["code"]No
client_namestringOptional human-readable name for the client--No

digital_credentials

Path: .verifier.digital_credentials

FieldTypeDescriptionExampleDefaultRequired
enableboolW3C Digital Credentials API support in browser-falseNo
use_jarboolJWT Authorization Request (JAR) for wallet communication When true, request objects are signed JWTs instead of plain JSON-falseNo
preferred_formats[]stringThe order of preference for credential formats Supported values: "vc+sd-jwt", "dc+sd-jwt", "mso_mdoc" Default: ["vc+sd-jwt", "dc+sd-jwt", "mso_mdoc"]-["vc+sd-jwt", "dc+sd-jwt", "mso_mdoc"]No
response_modestringThe OpenID4VP response mode for DC API flows Supported values: "dc_api.jwt" (encrypted), "direct_post.jwt" (signed), "direct_post" Default: "dc_api.jwt"-dc_api.jwtNo
allow_qr_fallbackboolAutomatic fallback to QR code if DC API is unavailable Default: true-trueNo
deep_link_schemestringDeepLinkScheme for mobile wallet integration"eudi-wallet://"-No

authorization_page_css

Path: .verifier.authorization_page_css

FieldTypeDescriptionExampleDefaultRequired
custom_cssstringInline CSS that will be injected into the authorization page Allows deployers to override default styling without modifying templates--No
css_filestringPath to an external CSS file to include If both CustomCSS and CSSFile are provided, both are included--No
themestringPredefined color scheme: "light" (default), "dark", "blue", "purple"-lightNo
primary_colorstringPrimaryColor overrides the primary brand color"#667eea"-No
secondary_colorstringSecondaryColor overrides the secondary brand color"#764ba2"-No
logo_urlstringA URL to a custom logo image--No
titlestringTitle overrides the page title (default: "Wallet Authorization")--No
subtitlestringSubtitle overrides the page subtitle--No

credential_display

Path: .verifier.credential_display

FieldTypeDescriptionExampleDefaultRequired
enableboolUsers to optionally view credential details before completing authorization When enabled, a checkbox appears on the authorization page-falseNo
require_confirmationboolUsers to review credentials before proceeding When true, the credential display step is mandatory (checkbox is pre-checked and disabled)-falseNo
show_raw_credentialboolThe raw VP token/credential in the display page Useful for debugging and technical users-falseNo
show_claimsboolThe parsed claims that will be sent to the RP Recommended for transparency and user consent-trueNo
allow_editboolUsers to redact certain claims before sending to RP (future feature) Currently not implemented-falseNo

presets entry

Path: .verifier.presets.<preset label>.<scope>

FieldTypeDescriptionExampleDefaultRequired
claimsarraySpecific claims to request. If empty, all VCTM claims are used.--No
exclude_claimsarrayClaims to exclude from the DCQL query.--No
validationsarrayOptional rules applied server-side after claims extraction--No

claims entry

Path: .verifier.presets.<preset label>.<scope>.claims[], .verifier.presets.<preset label>.<scope>.exclude_claims[]

FieldTypeDescriptionExampleDefaultRequired
path[]stringClaim path segments["birthdate"], ["address", "locality"]-Yes

validations entry

Path: .verifier.presets.<preset label>.<scope>.validations[]

FieldTypeDescriptionExampleDefaultRequired
rulestringValidation rule to apply, e.g., "age_over"."age_over"-Yes
path[]stringClaim path to validate, e.g., ["birthdate"].["birthdate"]-Yes
valueobjectThreshold or expected value for the validation.18-Yes

combined_presentation

Path: .verifier.combined_presentation

FieldTypeDescriptionExampleDefaultRequired
enabledboolEnabled activates combined presentation binding verification.--No
enforcementstring (enforce|warn|disabled)Enforcement determines how binding verification results are handled: - "enforce": reject the presentation if binding cannot be established - "warn": log a warning but allow the presentation through (per ARF 3.0 ACP_08) - "disabled": skip binding verification entirely-warnNo
binding_attributesarrayAttribute-based binding checks.--No
key_binding_enabledboolKeyBindingEnabled activates key-based binding (cnf.jwk / device key comparison). Cross-format comparison (SD-JWT cnf.jwk vs mDoc device key) is always supported since both are converted to RFC 7638 JWK thumbprints.--No

binding_attributes entry

Path: .verifier.combined_presentation.binding_attributes[]

FieldTypeDescriptionExampleDefaultRequired
paths[]stringClaim paths that must ALL match across credentials (AND semantics).["family_name", "birth_date", "place_of_birth.locality"]-Yes

revocation

Path: .verifier.revocation

FieldTypeDescriptionExampleDefaultRequired
enabledboolEnabled activates revocation status checking for presented credentials.--No
cache_ttlintDuration in seconds to cache fetched status list tokens.-300No
fail_openboolFailOpen determines behavior when the status list is unreachable or unparseable: - true: log warning and allow the credential through (fail-open) - false: reject the credential (fail-closed) Note: explicitly revoked/suspended credentials are always rejected regardless of this setting.-trueNo
skip_scopes[]stringCredential scopes exempt from revocation checking (e.g., short-lived credentials valid < 24 hours per ARF 3.0 §6.6.3.7).--No

zk_circuits

Path: .verifier.zk_circuits

(pkg/mdoc/zkcircuit) used to resolve a presented "mso_mdoc_zk" document's zkSystemId to a downloadable circuit artifact.

FieldTypeDescriptionExampleDefaultRequired
sources[]stringZk-circuits catalog mirror base URLs, tried in order until one succeeds (see pkg/mdoc/zkcircuit.Client - these are mirrors of the SAME catalog, not distinct registries). Defaults to the live deployed service if empty.["https://zk-circuits.fly.dev"]["https://zk-circuits.fly.dev"]No

registry (Top-level)

Configuration for the Registry service that manages credential status.

registry

Path: .registry

FieldTypeDescriptionExampleDefaultRequired
api_serverobjectHTTP API server configuration--Yes
public_urlstringPublic URL of this service (must be valid HTTP/HTTPS URL)"https://registry.sunet.se"-Yes
grpc_serverobjectGRPC server configuration--Yes
token_status_listsobjectToken Status List configuration--Yes
admin_guiobjectAdmin GUI configuration--No

token_status_lists

Path: .registry.token_status_lists

FieldTypeDescriptionExampleDefaultRequired
key_configobjectKey configuration for signing Token Status List tokens.--Yes
token_refresh_intervalint64How often (in seconds) new Token Status List tokens are generated. Default: 43200 (12 hours). Min: 301 (>5 minutes), Max: 86400 (24 hours)-43200No
section_sizeint64Number of entries (decoys) per section. Default: 1000000 (1 million)-1000000No
rate_limit_requests_per_minuteintMaximum requests per minute per IP for token status list endpoints. Default: 60-60No

admin_gui

Path: .registry.admin_gui

FieldTypeDescriptionExampleDefaultRequired
enableboolThe admin GUI-falseNo
usernamestringAdmin username-adminNo
passwordstringAdmin password--Yes (if enabled)

Secrets File Reference

The structure of the separate secrets file.

Secrets file structure

Path: (root)

When Common.SecretFilePath is set, ApplySecrets merges these values into the main config: the Mongo URI is only used when the main config has none. For each service section (apigw, registry, verifier) that is present in the secrets file, the corresponding secret fields in the main config are cleared and replaced by the secrets-file values. Sections omitted from the secrets file are left untouched.

FieldTypeDescriptionExampleDefaultRequired
commonobjectCommon--No
apigwobjectAPIGW--No
registryobjectRegistry--No
verifierobjectVerifier--No

common

Path: .common

FieldTypeDescriptionExampleDefaultRequired
mongoobjectMongo--No
sqlobjectSQL--No

mongo

Path: .common.mongo

FieldTypeDescriptionExampleDefaultRequired
uristringMongoDB connection string, which may include authentication credentials--No

sql

Path: .common.sql

FieldTypeDescriptionExampleDefaultRequired
postgresobjectPostgres connection password--No
mariadbobjectMariaDB connection password--No

postgres

Path: .common.sql.postgres

FieldTypeDescriptionExampleDefaultRequired
passwordstringPostgres connection password--No

mariadb

Path: .common.sql.mariadb

FieldTypeDescriptionExampleDefaultRequired
passwordstringMariaDB connection password--No

apigw

Path: .apigw

FieldTypeDescriptionExampleDefaultRequired
api_serverobjectAPI Server--No
auth_providersobjectAuth Providers--No

api_server

Path: .apigw.api_server

FieldTypeDescriptionExampleDefaultRequired
api_authobjectAPI Auth--No

api_auth

Path: .apigw.api_server.api_auth

FieldTypeDescriptionExampleDefaultRequired
oidcobjectOIDC--No

oidc

Path: .apigw.api_server.api_auth.oidc

FieldTypeDescriptionExampleDefaultRequired
client_secretstringOAuth2 client secret for the OIDC provider--No

auth_providers

Path: .apigw.auth_providers

FieldTypeDescriptionExampleDefaultRequired
oidcobjectOIDC--No

oidc

Path: .apigw.auth_providers.oidc

FieldTypeDescriptionExampleDefaultRequired
registrationobjectRegistration--No

registration

Path: .apigw.auth_providers.oidc.registration

FieldTypeDescriptionExampleDefaultRequired
preconfiguredobjectPreconfigured--No
dynamicobjectDynamic--No

preconfigured

Path: .apigw.auth_providers.oidc.registration.preconfigured

FieldTypeDescriptionExampleDefaultRequired
client_secretstringShared secret for the pre-configured OIDC RP client--No

dynamic

Path: .apigw.auth_providers.oidc.registration.dynamic

FieldTypeDescriptionExampleDefaultRequired
initial_access_tokenstringBearer token required by the OP for dynamic client registration--No

registry

Path: .registry

FieldTypeDescriptionExampleDefaultRequired
admin_guiobjectAdmin GUI--No

admin_gui

Path: .registry.admin_gui

FieldTypeDescriptionExampleDefaultRequired
passwordstringAdmin GUI login password--No

verifier

Path: .verifier

FieldTypeDescriptionExampleDefaultRequired
outboundobjectOutbound--No

outbound

Path: .verifier.outbound

FieldTypeDescriptionExampleDefaultRequired
oidc_providerobjectOIDC Provider--No

oidc_provider

Path: .verifier.outbound.oidc_provider

FieldTypeDescriptionExampleDefaultRequired
subject_saltstringSecret value used to derive pairwise subject identifiers for OIDC clients--No
static_clientsobjectClient_id to client_secret for static OIDC clients. Only clients listed here will have their secrets applied; clients not present in this map keep whatever value the main config provides (which will be empty after ApplySecrets clears them).<client_id>: "<client_secret>"-No

Example secrets.yaml

Path: file referenced by .common.secret_file_path

common:
mongo:
uri: "mongodb://user:password@mongo:27017/vc"
sql:
postgres:
password: "change-me-in-production"
mariadb:
password: "change-me-in-production"
apigw:
api_server:
api_auth:
oidc:
client_secret: "your-oidc-client-secret"
auth_providers:
oidc:
registration:
preconfigured:
client_secret: "your-oidc-client-secret"
dynamic:
initial_access_token: "<secret-value>"
registry:
admin_gui:
password: "change-me-in-production"
verifier:
outbound:
oidc_provider:
subject_salt: "random-salt-for-pairwise-subjects"
static_clients:
<client_id>: "<client_secret>"