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, and the Pushed Authorization Request (PAR) policy.

File Location

waltid-services/waltid-issuer-api2/config/issuer-service.conf

Configuration Options

PropertyTypeRequiredDefaultDescription
baseUrlStringYesPublic URL where the issuer service is reachable.
ciTokenKeyStringNoGenerated secp256r1 JWKSerialized key used to sign/verify OAuth2 access & refresh tokens.
enforcePushedAuthorizationRequestsBooleanNofalseRequire 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-known metadata, 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:7002"

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.

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:7002"

# 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: require Pushed Authorization Requests
enforcePushedAuthorizationRequests = false

Production Configuration

For production deployments, ensure:

  1. baseUrl points to your public HTTPS URL.
  2. ciTokenKey is set to a securely generated, persistent key (consider a KMS backend such as aws-rest-api, azure-rest-api or tse rather than an inline JWK).
# Production example
baseUrl = "https://issuer.example.com"
ciTokenKey = """{"type":"jwk","jwk":{"kty":"EC","d":"...","crv":"P-256","x":"...","y":"..."}}"""
enforcePushedAuthorizationRequests = true

These concerns are configured in their own files, not in issuer-service.conf:

Last updated on July 1, 2026