Issuer Service Configuration
The issuer-service.conf file configures core Issuer2 service settings: the service's public URL, the key used to sign OAuth2 tokens, optional credential encryption support, and the Pushed Authorization Request (PAR) policy.
File Location
waltid-services/waltid-issuer-api2/config/issuer-service.conf
Configuration Options
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
baseUrl | String | Yes | – | Public URL where the issuer service is reachable. |
ciTokenKey | String | No | Generated secp256r1 JWK | Serialized key used to sign/verify OAuth2 access & refresh tokens. |
credentialEncryptionKey | String | No | Not set | Serialized EC P-256 private key used for OID4VCI Credential Request decryption and Credential Response encryption. |
enforcePushedAuthorizationRequests | Boolean | No | false | Require clients to use the Pushed Authorization Request (PAR) endpoint. |
baseUrl
The public URL where the issuer service is accessible. Every OpenID4VCI endpoint is derived from it:
- The credential issuer base and metadata URLs become
"<baseUrl>/openid4vci". This is what is written into credential offers and the.well-knownmetadata, so it must be the URL wallets can actually reach. - The external OAuth callback becomes
"<baseUrl>/openid4vci/external/oauth/callback".
Trailing slashes are trimmed automatically.
baseUrl = "http://localhost:7005"
When running via Docker Compose, environment interpolation is supported:
baseUrl = "http://${SERVICE_HOST}:${ISSUER_API2_PORT}"
ciTokenKey
The key used to sign and verify the OAuth2 access tokens and refresh tokens issued by the service's token endpoint.
The value is a serialized walt.id key — the same format used elsewhere in walt.id — provided as a single JSON string. The type field selects the key backend and is required; omitting it causes startup to fail. Because the value is a string (not a HOCON object), use a triple-quoted HOCON string so the inner quotes do not need escaping:
ciTokenKey = """{"type":"jwk","jwk":{"kty":"EC","d":"...","crv":"P-256","x":"...","y":"..."}}"""
Supported type values include jwk (local key), tse (HashiCorp Vault Transit), aws-rest-api (AWS KMS), azure-rest-api (Azure Key Vault) and oci-rest-api (Oracle Cloud KMS).
Generating a key
The simplest way to get a stable local JWK in exactly the format above is a one-line Node.js command. It is identical on macOS, Linux, and Windows (PowerShell or cmd):
node -e "const{generateKeyPairSync}=require('crypto');const{privateKey}=generateKeyPairSync('ec',{namedCurve:'P-256'});const q=String.fromCharCode(34).repeat(3);console.log('ciTokenKey = '+q+JSON.stringify({type:'jwk',jwk:privateKey.export({format:'jwk'})})+q)"
It prints the complete config line — triple-quoted and ready to paste straight into issuer-service.conf, for example:
ciTokenKey = """{"type":"jwk","jwk":{"kty":"EC","x":"...","y":"...","crv":"P-256","d":"..."}}"""
Generate your own — never reuse the example value from these docs.
If you don't have Node installed, you can instead simply omit ciTokenKey: the service generates a key automatically on startup. Note the limitation described below.
If omitted, a new secp256r1 JWK is generated on every startup. This is fine for local development, but not for production: the signing key changes on each restart, so any tokens issued before a restart can no longer be verified. Always set ciTokenKey explicitly in real deployments.
credentialEncryptionKey
credentialEncryptionKey enables OID4VCI Credential Request encryption and Credential Response encryption.
Issuer2 supports this profile:
- Key type: EC P-256
- JWE
alg:ECDH-ES - JWE
enc:A128GCM - Compression: not supported
When configured, issuer metadata includes credential_request_encryption and credential_response_encryption with encryption_required = false.
Wallets can keep using normal JSON credential requests. Wallets that send an encrypted Credential Request as application/jwt and include credential_response_encryption receive the Credential Response as an encrypted JWE.
Use a dedicated key for credential encryption. Do not reuse the token signing key or credential signing keys.
credentialEncryptionKey = """{"type":"jwk","jwk":{"kty":"EC","crv":"P-256","x":"...","y":"...","d":"..."}}"""
enforcePushedAuthorizationRequests
Controls the OAuth2 Pushed Authorization Request (PAR, RFC 9126) policy for the authorization code flow. Defaults to false.
When true, clients must submit authorization parameters to the PAR (/par) endpoint instead of passing them directly to /authorize.
Leave this false unless you specifically need to mandate PAR.
enforcePushedAuthorizationRequests = false
Example Configuration
# issuer-service.conf
baseUrl = "http://localhost:7005"
# Optional: provide a stable token signing key (recommended for anything beyond local dev)
ciTokenKey = """{"type":"jwk","jwk":{"kty":"EC","d":"...","crv":"P-256","x":"...","y":"..."}}"""
# Optional: enable OID4VCI Credential Request/Response encryption
credentialEncryptionKey = """{"type":"jwk","jwk":{"kty":"EC","crv":"P-256","x":"...","y":"...","d":"..."}}"""
# Optional: require Pushed Authorization Requests
enforcePushedAuthorizationRequests = false
Production Configuration
For production deployments, ensure:
baseUrlpoints to your public HTTPS URL.ciTokenKeyis set to a securely generated, persistent key (consider a KMS backend such asaws-rest-api,azure-rest-apiortserather than an inline JWK).- If encrypted Credential Requests or encrypted Credential Responses are required, set
credentialEncryptionKeyto a dedicated EC P-256 private key.
# Production example
baseUrl = "https://issuer.example.com"
ciTokenKey = """{"type":"jwk","jwk":{"kty":"EC","d":"...","crv":"P-256","x":"...","y":"..."}}"""
credentialEncryptionKey = """{"type":"jwk","jwk":{"kty":"EC","crv":"P-256","x":"...","y":"...","d":"..."}}"""
enforcePushedAuthorizationRequests = true
Related Configuration
These concerns are configured in their own files, not in issuer-service.conf:
- Credential Issuer Metadata – OID4VCI metadata configuration (
credential-issuer-metadata.conf) - Issuer Profiles – Credential profiles, including issuer signing keys and DIDs (
issuer2-profiles.conf)
