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

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


auth.conf
# Will secure login cookies with `Secure` context, enable HTTS 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
    }
    success = true
  }
]

externalRoleMapping = {
  enabled = true
  strict = true
  mappings = [
    # acme tenant mapping
    { externalRole = "acme-tenant-admin", roleId = "waltid.acme.BW_ADMIN" },
    { externalRole = "acme-wallet-operator", roleId = "waltid.acme.BW_OPERATOR" },
    { externalRole = "acme-wallet-user", roleId = "waltid.acme.BW_USER" },

    # globex tenant mapping
    { externalRole = "globex-tenant-admin", roleId = "waltid.globex.BW_ADMIN" },
    { externalRole = "globex-wallet-operator", roleId = "waltid.globex.BW_OPERATOR" },
    { externalRole = "globex-wallet-user", roleId = "waltid.globex.BW_USER" }
  ]
}

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

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

AWS

{
  "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 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

  • method = "email": enables email/password login.
  • expiration = "7d" (optional): login token validity duration.
  • success = true: marks this flow as a successful terminal method.

OIDC flow fields (method = "oidc")

  • openIdConfigurationUrl: URL to the IdP OpenID Connect discovery document.
  • clientId: OIDC client ID registered at your IdP.
  • clientSecret: OIDC client secret.
  • callbackUri: callback URL handled by Enterprise Stack after IdP login.
  • accountIdentifierClaim: claim used to uniquely identify and link the external account (commonly sub).
  • pkceEnabled: enables PKCE (recommended).
  • success = true: marks this flow as a successful terminal method.

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

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.

Fields

  • enabled: turns external role mapping on/off.
  • strict:
    • true: authentication fails if no configured mapping matches received external roles.
    • false: unmapped external roles are ignored.
  • mappings: list of { externalRole, roleId } entries.

Mapping entry format

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

Example explanation

{ externalRole = "acme-wallet-operator", roleId = "waltid.acme.BW_OPERATOR" }

This means: if the IdP asserts acme-wallet-operator, the authenticated user gets Enterprise role waltid.acme.BW_OPERATOR.

Tenant-aware mapping

In multi-tenant deployments, define tenant-scoped role IDs (waltid.<tenant>.<role>) and map each tenant’s external roles explicitly, as shown in the example config above.

Last updated on March 10, 2026