---
title: "Auth"
description: "This configuration file controls user authentication, password management, token expiration, external identity provider (OIDC) login, and external role-to-enterprise-role mapping."
stack: "Enterprise Stack (commercial) — 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/enterprise-stack/setup/configurations/config-files/auth
generated: 2026-07-20
---
# Auth

This configuration file controls user authentication, password management, token expiration, external identity provider (OIDC) login, and external role-to-enterprise-role mapping.

### Example File

**Error:**

`signingKey`, `verificationKey`, `pepper`, and all OIDC settings are example values and must be replaced.

<br/>

```[auth.conf]
# Will secure login cookies with `Secure` context, enable HTTPS and HTTP->HTTPS redirect
requireHttps = false

# Key (all waltid-crypto supported) to sign login token - has to be key allowing signing (private key)
signingKey = {"type": "jwk", "jwk": {"kty": "OKP", "d": "L_2RuCSFUu818ZzM6Xml6uxesqTcxo8323-Q2S_qq4c", "use": "sig", "crv": "Ed25519", "x": "vvCN3xMAb0ZCt4sWIdtKDhkVHSERJZeBxybN-eSRkgw", "alg": "EdDSA"}}

# Key (all waltid-crypto supported) to verify incoming login tokens - public key is ok.
verificationKey = {"type": "jwk", "jwk": {"kty": "OKP", "d": "L_2RuCSFUu818ZzM6Xml6uxesqTcxo8323-Q2S_qq4c", "use": "sig", "crv": "Ed25519", "x": "vvCN3xMAb0ZCt4sWIdtKDhkVHSERJZeBxybN-eSRkgw", "alg": "EdDSA"}}

# Provide pepper to use for additional password salting (unique string for your deployment,
# has to be shared between instances).
pepper = "waltid-enterprise12345678"

# Hash algorithm to use for passwords for signing.
# You can choose from algorithms like: ARGON2, PBKDF2, PBKDF2_COMPRESSED, BCRYPT, SCRYPT, BALLON_HASHING, MESSAGE_DIGEST, NONE
hashAlgorithm = ARGON2

# If you previously used other (older) password hash algorithms, you
# can use this function to migrate old hashes to new hash algorithms. This
# works at login-time: When a user logs in with a password that uses a hash algorithm
# on this list, the password will be re-hashed in the specified replacement algorithm.
# If null is used as hash algorithm selector, all algorithms expect for the target
# algorithm will be converted automatically.
hashMigrations = {
    MESSAGE_DIGEST: ARGON2 # E.g.: Convert all the MD5 hashes to Argon2 hashes
}

authFlows = [
  {
    method = "email"
    expiration = "7d"
    success = true
  },
  {
    method = "oidc"
    config = {
      openIdConfigurationUrl = "http://keycloak:8080/realms/waltid/.well-known/openid-configuration"
      clientId = "waltid_enterprise"
      clientSecret = "waltid-enterprise-dev-secret"
      callbackUri = "http://waltid.enterprise.localhost:3000/auth/account/oidc/callback"
      accountIdentifierClaim = "sub"
      pkceEnabled = true
      
      # Post-login redirect (optional)
      redirectAfterLogin = "http://localhost:5180/"
      allowedRedirectUrls = [
        "http://localhost:5180/*",
        "http://demo.enterprise.localhost:5180/*"
      ]
      
      # Post-logout redirect (optional)
      postLogoutRedirectUri = "http://localhost:5180/"
      allowedPostLogoutRedirectUrls = [
        "http://localhost:5180/*"
      ]
      
      # External role extraction from OIDC tokens (optional)
      externalRoleExtraction = {
        enabled = true
        realmRolesClaimPath = "realm_access.roles"
        clientRolesClaimPath = "resource_access"
      }
    }
    success = true
  }
]

# External role mapping (OPTIONAL - can be managed via API instead)
# externalRoleMapping = {
#   enabled = true
#   strict = true
#   mappings = [
#     { externalRole = "tenant-admin", roleId = "waltid.tenant1.BW_ADMIN" }
#   ]
# }
```

## Signing & Verification Keys

When users log into the Enterprise Stack, authentication tokens (JWTs) are generated. These tokens are signed with a private key (`signingKey`) and verified using a public key (`verificationKey`). Both keys are defined in `auth.conf`.

### Why Signing & Verification Keys?

In multi-instance deployments, tokens issued in one instance must be verifiable in another. To make this work reliably, all instances must use the same signing/verification key pair.

### Types of Signing & Verification Keys

`signingKey` and `verificationKey` can be provided as a local key (RAW JWK) or a reference to an external KMS-managed key (for example AWS KMS).

### Examples

**Local**

```json
{
  "type": "jwk",
  "jwk": {
    "kty": "OKP",
    "d": "L_2RuCSFUu818ZzM6Xml6uxesqTcxo8323-Q2S_qq4c",
    "use": "sig",
    "crv": "Ed25519",
    "x": "vvCN3xMAb0ZCt4sWIdtKDhkVHSERJZeBxybN-eSRkgw",
    "alg": "EdDSA"
  }
}
```

**AWS**

```json
{
  "type": "aws",
  "config": {
    "auth": {
      "roleName": "AccessRole",
      "region": "eu-central-1"
    }
  },
  "id": "324ebf67-6bcc-4439-8b81-260bf0a82532",
  "_publicKey": "{\"kty\":\"EC\",\"crv\":\"P-256\",\"x\":\"RfvJGDXOjz3NOSKgZ0VlijXST8S-j96DrG0C1AMNAK8\",\"y\":\"vSt2q7yIy0-AhAirMuuDmUScxkgf4JVfId-vTETraQA\"}",
  "_keyType": "secp256r1"
}
```

## Auth Flows

The Enterprise Stack uses [waltid-ktor-authnz](https://github.com/walt-id/waltid-identity/tree/main/waltid-libraries/auth/waltid-ktor-authnz) for authentication and supports multiple methods in sequence via `authFlows`.

### Why `authFlows` (plural)

Use `authFlows` as a list of supported login methods. Typical enterprise setups include both:
- `email` (local account login)
- `oidc` (external identity provider login)

### Email flow fields

| Field | Required | Description |
|-------|----------|-------------|
| `method` | Yes | Set to `"email"` for email/password login |
| `expiration` | No | Login token validity duration (e.g., `"7d"`) |
| `success` | Yes | Set to `true` to mark as successful terminal method |

### OIDC flow fields (`method = "oidc"`)

| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `openIdConfigurationUrl` | Yes | — | URL to the IdP OpenID Connect discovery document |
| `clientId` | Yes | — | OIDC client ID registered at your IdP |
| `clientSecret` | Yes | — | OIDC client secret |
| `callbackUri` | Yes | — | Callback URL handled by Enterprise Stack after IdP login |
| `accountIdentifierClaim` | No | `"sub"` | Claim used to uniquely identify the external account |
| `pkceEnabled` | No | `true` | Enables PKCE (recommended) |
| `redirectAfterLogin` | No | — | Default URL to redirect after successful login |
| `allowedRedirectUrls` | No | `[]` | Allowed patterns for client-specified `redirect_to` parameter |
| `postLogoutRedirectUri` | No | — | Default URL to redirect after logout |
| `allowedPostLogoutRedirectUrls` | No | `[]` | Allowed patterns for client-specified post-logout redirects |
| `externalRoleExtraction` | No | — | Configuration for extracting roles from OIDC tokens |
| `success` | Yes | — | Set to `true` to mark as successful terminal method |

### Dynamic Redirect URLs

Clients can specify where to redirect after login by passing a `redirect_to` query parameter:

```
GET /auth/account/oidc/auth?redirect_to=https://app.example.com/callback
```

The URL is validated against `allowedRedirectUrls` patterns. Wildcards are supported:
- `"https://app.example.com/*"` — allows any path under this origin
- `"https://*.example.com/callback"` — allows subdomains

If no `redirect_to` is specified or validation fails, `redirectAfterLogin` is used as fallback.

### OIDC Logout

The Enterprise Stack supports RP-Initiated Logout. Call the logout endpoint:

```
GET /auth/account/oidc/logout?post_logout_redirect_uri=https://app.example.com/
```

This terminates the local session and returns the IdP's `end_session_url` for full SSO logout.

### External Role Extraction (`externalRoleExtraction`)

Extract roles from OIDC ID tokens (e.g., Keycloak realm/client roles):

| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `enabled` | No | `false` | Enable role extraction from OIDC tokens |
| `realmRolesClaimPath` | No | `"realm_access.roles"` | JSON path to realm roles in the ID token |
| `clientRolesClaimPath` | No | `"resource_access"` | JSON path to client roles in the ID token |
| `clientId` | No | (parent clientId) | Client ID for filtering client roles |

**Info:**

The `clientId` in `externalRoleExtraction` defaults to the parent `config.clientId`, so you typically don't need to specify it.

### Duration format for `expiration`

Set expiration using kotlinx.datetime duration syntax (for example `5h`, `1d 12h`, `1h 0m 30.340s`) or simplified ISO-8601 duration (`P1DT2H3M4.058S`).

**Note:**

Expiration applies to login tokens issued through account login. API key expiration is configured separately in API key settings.

## External Role Mapping (`externalRoleMapping`)

Use `externalRoleMapping` to map roles from an external IdP (for example Keycloak roles/groups) to Enterprise Stack role IDs.

**Info:**

**This section is optional.** External role mappings can also be managed via the REST API (database), which is recommended for production deployments as it allows changes without restarting the server.

### Fields

| Field | Required | Default | Description |
|-------|----------|---------|-------------|
| `enabled` | No | `false` | Turns external role mapping on/off |
| `strict` | No | `true` | If `true`, authentication fails when no mapping matches |
| `expectedIssuer` | No | — | Only accept tokens from this issuer |
| `expectedClientId` | No | — | Only map roles from this client |
| `mappings` | No | `[]` | List of `{ externalRole, roleId }` entries |

### Mapping entry format

- `externalRole`: role value received from the external provider.
- `roleId`: Enterprise Stack role identifier to assign.

### Example

```hocon
externalRoleMapping = {
  enabled = true
  strict = true
  expectedIssuer = "http://keycloak:8080/realms/waltid"
  mappings = [
    { externalRole = "tenant-admin", roleId = "waltid.tenant1.BW_ADMIN" },
    { externalRole = "wallet-operator", roleId = "waltid.tenant1.BW_OPERATOR" }
  ]
}
```

This means: if the IdP asserts `tenant-admin`, the authenticated user gets Enterprise role `waltid.tenant1.BW_ADMIN`.

### Config vs API Mappings

External role mappings can be managed in two ways:

1. **Config file** (`auth.conf`): Define mappings in the `externalRoleMapping` section. Requires restart to change.

2. **REST API** (recommended): Create mappings via the roles API:
   ```bash
   curl -X PUT \
     'https://{host}/v1/{roleId}/roles-api/roles/external-mappings/{externalRole}' \
     -H 'Authorization: Bearer {token}' \
     -d '{"enabled": true}'
   ```

**Resolution order:**
1. Database mappings are checked first
2. If database has any mappings, those are used (config is ignored)
3. If database has no mappings, config-based mappings are used as fallback

### Tenant-aware mapping

In multi-tenant deployments, define tenant-scoped role IDs (`waltid.<tenant>.<role>`) and map each tenant's external roles explicitly:

```hocon
mappings = [
  # acme tenant
  { externalRole = "acme-tenant-admin", roleId = "waltid.acme.BW_ADMIN" },
  { externalRole = "acme-wallet-operator", roleId = "waltid.acme.BW_OPERATOR" },
  
  # globex tenant
  { externalRole = "globex-tenant-admin", roleId = "waltid.globex.BW_ADMIN" },
  { externalRole = "globex-wallet-operator", roleId = "waltid.globex.BW_OPERATOR" }
]
```
