---
title: "Issuer Service"
description: "Reference for the issuer-service.conf configuration file."
stack: "Community Stack (open source) — version 0.21.0"
stack_version: "0.21.0"
stack_comparison: https://docs.walt.id/community-vs-enterprise.md
canonical_url: https://docs.walt.id/community-stack/issuer2/configurations/config-files/issuer-service
generated: 2026-07-20
---
# 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

| 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. |
| `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-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.

```hocon
baseUrl = "http://localhost:7002"
```

When running via Docker Compose, environment interpolation is supported:

```hocon
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:

```hocon
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](https://nodejs.org) command. It is identical on macOS, Linux, and Windows (PowerShell or cmd):

```bash
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:

```hocon
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.

**Error:**

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.

```hocon
enforcePushedAuthorizationRequests = false
```

## Example Configuration

```hocon
# 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).

```hocon
# Production example
baseUrl = "https://issuer.example.com"
ciTokenKey = """{"type":"jwk","jwk":{"kty":"EC","d":"...","crv":"P-256","x":"...","y":"..."}}"""
enforcePushedAuthorizationRequests = true
```

## Related Configuration

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

- [Credential Issuer Metadata](https://docs.walt.id/community-stack/issuer2/configurations/config-files/credential-issuer-metadata.md) – OID4VCI metadata configuration (`credential-issuer-metadata.conf`)
- [Issuer Profiles](https://docs.walt.id/community-stack/issuer2/configurations/config-files/issuer-profiles.md) – Credential profiles, including issuer signing keys and DIDs (`issuer2-profiles.conf`)
