Configuration Reference
Both the STS (Security Token Service) and Auth Bridge services are configured through application.yml files, with all custom properties nested under the sphereon.app.* prefix. Environment variables can be interpolated into the configuration using the ${env:VARIABLE_NAME:default_value} syntax, where the portion after the colon is the fallback value used when the environment variable is not set. Secrets are referenced via indirect references (*-ref.key) that resolve to environment variables at runtime, ensuring no plaintext secrets ever appear in configuration files.
This page provides a comprehensive reference for all configuration properties, organized by service and by functional section within each service.
Configuration Structure
The general structure of an application.yml file follows this pattern:
sphereon:
app:
section:
property: value
nested-section:
property: "${env:ENV_VAR:default_value}"
Environment variable interpolation is resolved at application startup. This approach allows the same configuration file to be used across environments (development, staging, production) by varying only the environment variables.
Configuration Precedence
Configuration values are resolved in the following order of precedence (highest to lowest):
- Environment variables set on the process or container
- System properties passed via
-DJVM flags - application.yml values in the working directory
- application.yml values bundled in the JAR
- Default values specified in the
${env:VAR:default}syntax
STS Configuration
The STS service handles OAuth2 authorization server functionality, token issuance, and federation with upstream identity providers. Its configuration is organized into the following sections.
OAuth2 Server Settings
These properties control the behavior of the OAuth2 authorization server built into the STS.
sphereon:
app:
oauth2:
servers:
primary:
mode: "HOSTED"
issuer: "${env:STS_ISSUER_URL:http://localhost:8092}"
access-token-lifetime-seconds: 3600 # 1 hour
refresh-token-lifetime-seconds: 86400 # 24 hours
id-token-lifetime-seconds: 3600 # 1 hour
pkce-mode: "REQUIRED" # Always require PKCE
dpop-mode: "DISABLED" # Disabled for PoC
token-exchange-mode: "SUPPORTED" # RFC 8693
introspection-mode: "SUPPORTED" # RFC 7662
| Property | Default | Description |
|---|---|---|
mode | HOSTED | Server mode. HOSTED means the STS operates as a full OAuth2 authorization server capable of issuing tokens. |
issuer | http://localhost:8092 | The issuer URL included in all issued tokens. Must match the externally reachable URL of the STS. This value appears in the iss claim of JWT tokens and must be consistent with the OIDC discovery document at /.well-known/openid-configuration. |
access-token-lifetime-seconds | 3600 | Lifetime of access tokens in seconds (1 hour). After this period, clients must use a refresh token or re-authenticate. |
refresh-token-lifetime-seconds | 86400 | Lifetime of refresh tokens in seconds (24 hours). |
id-token-lifetime-seconds | 3600 | Lifetime of ID tokens in seconds (1 hour). |
pkce-mode | REQUIRED | PKCE (Proof Key for Code Exchange) enforcement level. Valid values: REQUIRED (all clients must use PKCE), SUPPORTED (PKCE accepted but not mandatory), DISABLED. Should always be REQUIRED in production to prevent authorization code interception attacks. |
dpop-mode | DISABLED | DPoP (Demonstrating Proof of Possession) enforcement. REQUIRED provides sender-constrained tokens that cannot be replayed by an attacker who intercepts them. Recommended for production but disabled in the proof-of-concept configuration. |
token-exchange-mode | SUPPORTED | RFC 8693 token exchange support. Allows clients to exchange one token type for another. |
introspection-mode | SUPPORTED | RFC 7662 token introspection support. Allows resource servers to validate tokens by calling the STS. |
STS Client Registrations
Each registered OAuth2 client is configured under oauth2.servers.clients. Client registrations define which applications are permitted to request tokens from the STS and under what conditions.
clients:
- client-id: "portal"
client-secret-ref:
key: "STS_CLIENT_SECRET"
redirect-uris:
- "${env:FRONTEND_URL:http://localhost:3000}/api/auth/callback/sts"
- "${env:FRONTEND_URL:http://localhost:3000}/api/auth/callback/sts-wallet"
scopes: ["openid", "profile", "email"]
grant-types: ["authorization_code", "refresh_token"]
| Property | Description |
|---|---|
client-id | Unique identifier for the client application. Used in authorization requests and token exchanges. |
client-secret-ref.key | Environment variable name containing the client secret. The STS reads the value from this environment variable at runtime. Never hardcode the secret in the YAML file. |
redirect-uris | List of allowed redirect URIs for the authorization code flow. The STS rejects authorization requests with redirect URIs not in this list. Supports environment variable interpolation for the base URL. |
scopes | Allowed scopes that this client may request. Requests for scopes not in this list are rejected. |
grant-types | Allowed OAuth2 grant types. Common values are authorization_code (for interactive browser flows) and refresh_token (for silent token renewal). |
Federation Providers
Federation providers are upstream identity providers that the STS delegates authentication to. When a user chooses to authenticate via SURF or Keycloak, the STS acts as an OIDC relying party to the selected upstream provider.
federation:
providers:
surf:
issuer-url: "${env:SURF_ISSUER_URL:https://connect.test.surfconext.nl}"
client-id-ref:
key: "FEDERATION_CLIENT_ID"
client-secret-ref:
key: "FEDERATION_CLIENT_SECRET"
provider-id: "env"
scopes: ["openid", "profile", "email", "eduid"]
user-info-enabled: true
state-mode: "JWT"
keycloak:
enabled: "${env:KEYCLOAK_ENABLED:false}"
issuer-url: "${env:KEYCLOAK_ISSUER_URL:http://localhost:8083/realms/portal}"
client-id-ref:
key: "KEYCLOAK_CLIENT_ID"
client-secret-ref:
key: "KEYCLOAK_CLIENT_SECRET"
provider-id: "env"
scopes: ["openid", "profile", "email"]
| Property | Default | Description |
|---|---|---|
issuer-url | -- | OIDC issuer URL of the upstream provider. The STS appends /.well-known/openid-configuration to discover endpoints. |
client-id-ref.key | -- | Environment variable containing the OIDC client ID registered with this provider. |
client-secret-ref.key | -- | Environment variable containing the OIDC client secret. |
client-secret-ref.provider-id | env | Secret provider type. env reads from an environment variable. |
scopes | ["openid"] | Scopes to request from the upstream provider. SURF supports the eduid scope for eduID-specific claims. |
user-info-enabled | false | Whether to call the provider's UserInfo endpoint after token exchange to obtain additional claims. |
state-mode | RANDOM | How to generate the OIDC state parameter. JWT encodes session metadata in the state as a signed JWT; RANDOM uses a random opaque string. |
enabled | true | Whether this provider is active. Set to false to disable without removing the configuration. |
STS Auth Bridge Delegation
The STS delegates wallet-based authentication (OID4VP flows) to the Auth Bridge service. When a user presents a verifiable credential from their wallet, the STS forwards the presentation to the Auth Bridge for verification and identity matching.
oid4vp:
auth-bridge:
base-url: "${env:AUTH_BRIDGE_URL:http://localhost:8090}"
default-query-id: "portal-eduid-vc"
| Property | Default | Description |
|---|---|---|
oid4vp.auth-bridge.base-url | http://localhost:8090 | Internal base URL of the Auth Bridge service. Used for service-to-service communication. |
oid4vp.auth-bridge.default-query-id | portal-eduid-vc | The default DCQL query identifier to use when initiating OID4VP sessions. References a query defined in the Auth Bridge configuration. |
Identity Reconciliation Attribute Rules (STS)
The STS includes attribute rules that control how claims from different sources are assembled into tokens. These rules determine which claims appear in ID tokens and access tokens issued to clients.
See the Canonical Attribute Rules section below for the full definition and attribute table.
Auth Bridge Configuration
The Auth Bridge service is the core of the identity matching and reconciliation system. Its configuration is more extensive than the STS, covering OID4VP session management, cryptographic key management, reconciliation provider setup, database access, external API security, and data lifecycle management.
OID4VP Settings
These settings control how the Auth Bridge handles verifiable presentation sessions initiated by wallets.
sphereon:
app:
oid4vp:
universal:
external-base-url: "${env:AUTH_BRIDGE_EXTERNAL_URL:http://localhost:8090}"
auth-bridge:
session-ttl-seconds: 300 # 5-minute session timeout
require-reconciliation: true
| Property | Default | Description |
|---|---|---|
oid4vp.universal.external-base-url | http://localhost:8090 | The externally reachable base URL of the Auth Bridge. Used to construct authorization request URLs that are sent to wallets. Must be publicly accessible when wallets are external devices. |
oid4vp.auth-bridge.session-ttl-seconds | 300 | Lifetime in seconds of an OID4VP presentation session. After this period, the session expires and cannot be completed. The wallet holder must start a new session. |
oid4vp.auth-bridge.require-reconciliation | true | Whether identity reconciliation is mandatory. When true, wallet holders must complete the reconciliation flow (linking to an institutional identity) before a binding is created. When false, bindings are created from wallet data alone. |
DCQL Queries
DCQL (Digital Credentials Query Language) queries define what credential types and claims the Auth Bridge requests from wallets during OID4VP sessions.
oid4vp:
dcql-queries:
portal-eduid-vc:
credential-type: "eu.europa.ec.eudi.pid.1"
claims:
- "family_name"
- "given_name"
- "birth_date"
- "issuance_date"
Each query is identified by a unique ID (e.g., portal-eduid-vc) and specifies the credential type to request and the list of claims that should be included in the presentation. The STS references these query IDs when delegating OID4VP flows to the Auth Bridge.
KMS (Key Management Service)
The KMS configuration determines where cryptographic keys are stored and how the Auth Bridge accesses them. The system supports multiple KMS providers, allowing development environments to use a software-based keystore while production environments use a hardware-backed cloud KMS.
Software Provider (Development)
kms:
providers:
- id: "software"
type: "SOFTWARE"
config:
keystore-path: "data/keystore/auth-bridge.p12"
keystore-password-ref:
key: "KMS_KEYSTORE_PASSWORD"
The software provider stores keys in a PKCS#12 keystore file on the local filesystem. This is convenient for development but provides no hardware protection for key material and should never be used in production.
Azure Key Vault Provider (Production)
kms:
providers:
- id: "azure"
type: "AZURE_KEY_VAULT"
config:
vault-url: "https://your-vault.vault.azure.net"
tenant-id: "${env:AZURE_TENANT_ID}"
client-id: "${env:AZURE_CLIENT_ID}"
client-secret-ref:
key: "AZURE_CLIENT_SECRET"
| Property | Description |
|---|---|
vault-url | Azure Key Vault URL. |
tenant-id | Azure AD tenant ID for authentication. |
client-id | Azure AD application (service principal) client ID. |
client-secret-ref.key | Environment variable containing the Azure AD client secret. |
Azure Key Vault provides HSM-backed key storage, ensuring that key material never leaves the hardware security module boundary. Cryptographic operations (HMAC, encrypt, decrypt) are performed within the HSM.
Cryptographic Key Configuration
Three domain-separated keys are used throughout the system. Each key is referenced by an alias (its name in the KMS) and a version number that tracks key rotation.
identity:
reconciliation:
crypto:
holder-hmac-key-alias: "reconciliation:holder"
holder-hmac-key-version: 1
institution-hmac-key-alias: "reconciliation:institution"
institution-hmac-key-version: 1
encryption-key-alias: "reconciliation:encryption"
encryption-key-version: 1
# Uncomment during key rotation:
# previous-holder-hmac-key-alias: "reconciliation:holder-v1"
# previous-holder-hmac-key-version: 1
| Property | Default | Description |
|---|---|---|
crypto.holder-hmac-key-alias | -- | KMS key alias for Key A. Used for HMAC-SHA256 hashing of wallet/holder identifiers. |
crypto.holder-hmac-key-version | 1 | Current version of Key A. Stored on records so the system knows which version to use for verification. |
crypto.institution-hmac-key-alias | -- | KMS key alias for Key B. Used for HMAC-SHA256 hashing of institution identifiers. |
crypto.institution-hmac-key-version | 1 | Current version of Key B. |
crypto.encryption-key-alias | -- | KMS key alias for Key C. Used for AES-256-GCM encryption of sensitive data. |
crypto.encryption-key-version | 1 | Current version of Key C. |
crypto.previous-holder-hmac-key-alias | -- | Previous Key A alias, used during key rotation. The system will attempt to verify hashes against both the current and previous key. |
crypto.previous-holder-hmac-key-version | -- | Previous Key A version. |
Reconciliation Rules
The rule version is a date-stamped identifier that tracks when the reconciliation rules were last updated. This version is stored on each binding so that operators can determine which rule set was in effect when the binding was created.
rule-version: "2026-03-24"
selector-rules:
- id: "default-surf"
enabled: true
priority: 0
plan:
type: "RUN_IDV"
provider-id: "surf"
material-profile-id: "holder-only-v1"
Selector Rules
Selector rules determine which reconciliation provider is used for a given identity match. Rules are evaluated in priority order (lowest number = highest priority), and the first matching enabled rule is selected.
| Property | Description |
|---|---|
selector-rules[].id | Unique identifier for the rule. |
selector-rules[].enabled | Whether this rule is active. |
selector-rules[].priority | Evaluation order (0 = highest priority). |
selector-rules[].plan.type | Action type. RUN_IDV initiates identity verification with an upstream provider. |
selector-rules[].plan.provider-id | Which reconciliation provider to use (must match a provider ID in the providers list). |
selector-rules[].plan.material-profile-id | Which material profile to apply for determining binding staleness. |
Material Profiles
Material profiles define which attributes are considered "material" -- that is, which attributes are significant enough that a change in their values should trigger re-reconciliation of the binding.
material-profiles:
- id: "holder-only-v1"
version: "1"
materials:
- type: "holder_key_fp"
hmac-domain: "holder"
| Property | Description |
|---|---|
material-profiles[].id | Unique identifier for the profile. |
material-profiles[].version | Version of this profile. Stored on bindings for traceability. |
material-profiles[].materials | List of material definitions. Each material specifies a type and the HMAC domain used for fingerprinting. |
Reconciliation Providers
Each reconciliation provider represents an upstream identity verification source (such as SURF) that users authenticate with to link their wallet identity to an institutional identity.
oidc-clients:
surf-oidc:
discovery-url: "https://connect.test.surfconext.nl/.well-known/openid-configuration"
client-id-ref:
key: "IDENTITY_RECONCILIATION_PROVIDERS_SURF_CLIENT_ID"
client-secret-ref:
key: "IDENTITY_RECONCILIATION_PROVIDERS_SURF_CLIENT_SECRET"
provider-id: "env"
scopes: ["openid", "profile", "email", "eduid"]
user-info-enabled: true
providers:
- id: "surf"
name: "SURFconext"
oidc-client-id: "surf-oidc"
identifier-attribute-name: "sub"
enabled: true
The configuration separates OIDC client settings (oidc-clients) from provider definitions (providers). This allows multiple providers to share the same OIDC client if needed, or for a provider to be reconfigured to use a different OIDC client without changing its identity.
| Property | Default | Description |
|---|---|---|
oidc-clients[].discovery-url | -- | OIDC discovery endpoint URL for automatic endpoint discovery. |
oidc-clients[].client-id-ref.key | -- | Environment variable containing the OIDC client ID. |
oidc-clients[].client-secret-ref.key | -- | Environment variable containing the OIDC client secret. |
oidc-clients[].scopes | ["openid"] | Scopes to request during reconciliation. |
oidc-clients[].user-info-enabled | false | Whether to call UserInfo for additional claims. |
providers[].id | -- | Unique provider identifier. Referenced by selector rules and stored on bindings. |
providers[].name | -- | Display name shown to users during the reconciliation flow. |
providers[].oidc-client-id | -- | References an OIDC client definition from the oidc-clients section. |
providers[].identifier-attribute-name | sub | The claim name to use as the institution identifier. The value of this claim is HMAC-hashed with Key B and stored as institution_identifier_hash. |
providers[].enabled | true | Whether this provider is currently active. |
Database
database:
url: "${env:DATABASE_URL:jdbc:postgresql://localhost:5432/authbridge}"
username: "${env:DATABASE_USERNAME:postgres}"
password-ref:
key: "DATABASE_PASSWORD"
max-pool-size: 5
| Property | Default | Description |
|---|---|---|
database.url | jdbc:postgresql://localhost:5432/authbridge | JDBC connection URL for the Auth Bridge database. |
database.username | postgres | Database username. |
database.password-ref.key | -- | Environment variable containing the database password. |
database.max-pool-size | 5 | Maximum number of connections in the connection pool. Tune based on expected concurrency. |
External API
The external API allows authorized third-party systems to look up identity information. Access is controlled through JWT bearer tokens and client-specific attribute projections.
external-api:
enabled: true
jwt:
issuer: "${env:EXTERNAL_API_JWT_ISSUER:http://keycloak:8080/realms/portal}"
jwks-uri: "${env:EXTERNAL_API_JWT_JWKS_URI}"
clients:
api:
scopes: ["reconciliation:read"]
projected-claims: ["eduid", "eduperson_principal_name", "email"]
auxiliary-categories: ["enrollment", "role"]
| Property | Default | Description |
|---|---|---|
external-api.enabled | true | Whether the external API is active. |
external-api.jwt.issuer | -- | Expected iss claim in JWT bearer tokens. Tokens from other issuers are rejected. |
external-api.jwt.jwks-uri | -- | JWKS endpoint URL for validating JWT signatures. The Auth Bridge fetches the signing keys from this endpoint. |
external-api.clients[].scopes | -- | Required scopes in the JWT token for this client. |
external-api.clients[].projected-claims | -- | List of canonical attribute names this client is allowed to receive in identity lookup responses. Claims not in this list are filtered out even if they exist on the binding. |
external-api.clients[].auxiliary-categories | -- | List of auxiliary data categories this client may access. Requests for categories not in this list are denied. |
Client projections implement the principle of least privilege at the data level. Each API consumer sees only the attributes they need, even though the system may have more data available for the identity.
Retention and Cleanup
retention:
inactive-days: 730 # 2-year inactivity threshold
soft-delete-days: 30 # 30-day soft-delete retention
cleanup-interval-minutes: 60 # Inactivity check frequency
session-cleanup:
interval-minutes: 5 # Expired session cleanup frequency
session-ttl-seconds: 300 # Reconciliation session timeout
| Property | Default | Description |
|---|---|---|
retention.inactive-days | 730 | Number of days of inactivity after which a binding is soft-deleted. Based on the last_used_at timestamp. |
retention.soft-delete-days | 30 | Number of days a soft-deleted record is retained before permanent hard deletion. |
retention.cleanup-interval-minutes | 60 | How often (in minutes) the background job checks for inactive bindings. |
session-cleanup.interval-minutes | 5 | How often (in minutes) the background job cleans up expired reconciliation sessions. |
session-ttl-seconds | 300 | Default lifetime of a reconciliation session in seconds. |
Canonical Attribute Rules
Attribute rules control how claims from different sources (wallet credentials and OIDC providers) are merged, which claims are persisted in the encrypted binding envelope, and which claims are projected into STS tokens and API responses. Both the STS and Auth Bridge have attribute rules: the Auth Bridge rules govern persistence, while the STS rules govern token projection.
Merge Modes
| Mode | Behavior |
|---|---|
OIDC_WINS | Use the OIDC provider's value if available; fall back to the wallet credential value if the OIDC provider does not supply this claim. This is the default for most attributes, reflecting the higher assurance of institutionally verified data. |
WALLET_ONLY | Only use values from the wallet credential. OIDC provider values for this claim are ignored. Appropriate for claims that are inherent to the wallet identity itself. |
OIDC_ONLY | Only use values from the OIDC provider. Wallet credential values for this claim are ignored. Used for claims like eduid and sub that are definitionally tied to the institution. |
Auth Bridge Attribute Rules (Persistence)
The following table shows the complete set of canonical attributes as configured for the Auth Bridge. The persist column determines whether the attribute is stored (encrypted) in the binding's persisted_attributes_envelope. The project column determines whether the attribute is included in API responses and STS token assembly.
| Canonical Name | Merge Mode | Persist | Project | Source Aliases |
|---|---|---|---|---|
eduid | OIDC_ONLY | true | true | eduid |
eduperson_principal_name | OIDC_WINS | true | true | eduperson_principal_name, urn:mace:dir:attribute-def:eduPersonPrincipalName |
email | OIDC_WINS | true | true | email |
given_name | OIDC_WINS | false | true | given_name |
family_name | OIDC_WINS | false | true | family_name |
sub | OIDC_ONLY | true | true | sub |
schac_home_organization | OIDC_ONLY | true | true | schac_home_organization |
eduperson_affiliation | OIDC_WINS | true | true | eduperson_affiliation |
eduperson_scoped_affiliation | OIDC_WINS | true | true | eduperson_scoped_affiliation |
The data minimization principle is visible in the persist column: given_name and family_name have persist: false. These personally identifiable information (PII) fields are available during the active session -- they flow through the system and may appear in tokens issued by the STS -- but they are never written to the database. If the database is compromised, an attacker will find no names or other directly identifying PII, only encrypted institutional identifiers and affiliation data.
Source Aliases
The Source Aliases column lists all claim names that map to a given canonical attribute. Different OIDC providers may use different claim names for the same concept (e.g., eduperson_principal_name vs. the URN-based urn:mace:dir:attribute-def:eduPersonPrincipalName). The attribute mapping normalizes these into a single canonical name.
Secret References
Secrets are never stored in configuration files. Instead, they use indirect references that are resolved at runtime from environment variables:
# Reference an environment variable
client-secret-ref:
key: "ENVIRONMENT_VARIABLE_NAME"
provider-id: "env" # Optional, defaults to env
# The service reads the secret at runtime:
# System.getenv("ENVIRONMENT_VARIABLE_NAME")
This indirection pattern ensures that application.yml files can be safely committed to version control without exposing credentials. The actual secret values live exclusively in the runtime environment.
Production Secret Management
For production deployments, populate the environment variables from a dedicated secrets manager:
- Azure Key Vault: Use the Azure Key Vault CSI driver (Kubernetes) or Azure App Service key references to inject secrets as environment variables.
- AWS Secrets Manager: Use the AWS Secrets and Config Provider for Kubernetes, or ECS task definition secrets.
- HashiCorp Vault: Use the Vault Agent sidecar or CSI provider to inject secrets.
- Kubernetes Secrets: As a baseline, create Kubernetes Secret objects and reference them in pod specifications:
# In Kubernetes, the environment variable is populated from a Secret:
# envFrom:
# - secretRef:
# name: portal-secrets
Never commit .env files, .pem files, .key files, or any other files containing plaintext secrets to version control. The repository's .gitignore should include entries for all such file patterns.