Authentication Service Configuration

The authentication-service.conf file configures the external OAuth2 / OIDC provider (such as Keycloak, Microsoft Entra ID or Auth0) used for authorization-code-flow credential issuance. During that flow the issuer sends the user to this provider to log in, and then receives the user's claims (e.g. email, name) in return.

To use authorization code flow you configure your own OAuth/OIDC provider here — its endpoints, the client credentials the issuer uses to talk to it, and the scopes to request.

Just want to try it out? You don't need to set anything up. If you don't provide an authentication-service.conf, Issuer2 falls back to a hosted walt.id test identity provider with ready-made login accounts — see Default Test Provider below. Configure your own provider only when you move towards production.

File Location

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

When This Is Used

This configuration only matters when issuing credentials via authorization code flow. In that flow the issuer sends the user to the provider configured here to log in. The provider returns the user's claims (e.g. email, name) in an ID token, which can then be mapped into the credential.

For pre-authorized code flow (PIN-based issuance), this configuration is not used.

Default Test Provider

To let you try the authorization code flow immediately — without registering your own Keycloak, Entra, or Auth0 tenant — Issuer2 ships with built-in defaults that point at a hosted walt.id test identity provider (a Keycloak realm at keycloak.demo.walt.id). These defaults are used automatically whenever a value isn't set in authentication-service.conf, so if you never create that file, the authorization code flow works out of the box against this test provider.

You can then create an AUTHORIZED offer (see Create an Offer) and, when the wallet sends you to log in, sign in with one of the accounts below.

Test Users

UsernamePasswordClaims returned in the ID token
jane@walt.idjanegiven_name, family_name
max@walt.idpasswordclearanceLevel, employeeId, position, department, startDate

These claims are what the provider returns after login. To actually see them land in an issued credential, the credential profile needs an idTokenClaimsMapping that maps them into credential fields.

Try it end to end with jane: the ready-made identityCredentialSdJwt profile already maps given_name and family_name from the ID token. Create an AUTHORIZED offer for that profile, open it in a wallet, log in as jane@walt.id / jane, and the issued credential's given_name / family_name will be filled in from Jane's login instead of the profile's placeholder values.

max@walt.id returns a richer set of workplace claims (clearanceLevel, employeeId, position, department, startDate). No default profile maps these, so use max when you want to practise writing your own idTokenClaimsMapping against real ID-token claims.

The default test provider and these shared accounts are for local testing and demos only. They are public and unauthenticated for anyone running Issuer2, so never rely on them — or the built-in client secret — in production. Configure your own provider (see Example Configurations) before going live.

Configuration Options

Every option has a built-in default that points at the hosted test provider. You only need to set these when pointing Issuer2 at your own provider — at which point authorizeUrl, accessTokenUrl, clientId, and clientSecret are effectively required (the test-provider defaults won't match your setup).

PropertyTypeRequired for own providerDefaultDescription
authorizeUrlStringYesTest providerOAuth authorization endpoint. The user is sent here to authenticate.
accessTokenUrlStringYesTest providerToken endpoint where the issuer exchanges the authorization code for an access token and ID token.
clientIdStringYesTest providerOAuth client ID registered with the provider.
clientSecretStringYesTest providerOAuth client secret.
nameStringNo"keycloak"Provider name. Informational — passed through to the OAuth client settings.
defaultScopesArray<String>No["openid", "profile"]OAuth scopes requested during authorization.
forwardIssuerStateToAuthorizationServerBooleanNofalseWhether to forward the issuer's internal issuer_state to the authorization server.

name

Provider name. Informational only — it is passed through as the OAuth client's name and does not change behaviour.

name = "keycloak"

authorizeUrl

OAuth authorization endpoint URL. The user is redirected here to authenticate.

authorizeUrl = "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/auth"

accessTokenUrl

Token endpoint URL where the issuer exchanges the authorization code for an access token and ID token.

accessTokenUrl = "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token"

clientId

OAuth client ID registered with the provider.

clientId = "issuer_api"

clientSecret

OAuth client secret.

clientSecret = "secret-from-your-provider"

Never commit secrets to version control. Use environment variables or a secret manager.

defaultScopes

OAuth scopes requested during authorization. Common scopes:

  • openid – required for OIDC
  • profile – access to name and similar profile claims
  • email – access to the email address
defaultScopes = ["openid", "profile"]

forwardIssuerStateToAuthorizationServer

Controls whether the issuer's internal issuer_state value is forwarded to the authorization server as an extra issuer_state query parameter on the authorize request. Defaults to false.

This is only needed for custom integrations where the external authorization server has to receive the issuer state. When true, the issuer extracts issuer_state from the internal login request and appends it to the outgoing authorize URL (it is skipped if the value is missing, blank, or already present).

forwardIssuerStateToAuthorizationServer = false

Leave this false unless your provider specifically requires the forwarded state.

Redirect URI

The issuer's OAuth callback is derived from baseUrl (set in issuer-service.conf):

<baseUrl>/openid4vci/external/oauth/callback

Register this exact URL as an allowed redirect URI in your OAuth provider, otherwise the provider rejects the login. For example, with baseUrl = "https://issuer.example.com" the redirect URI is https://issuer.example.com/openid4vci/external/oauth/callback.

Example Configurations

Keycloak

# authentication-service.conf

name = "keycloak"
authorizeUrl = "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/auth"
accessTokenUrl = "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token"
clientId = "issuer_api"
clientSecret = "secret-from-keycloak"
defaultScopes = ["openid", "profile", "email"]
forwardIssuerStateToAuthorizationServer = false

Microsoft Entra ID (Azure AD)

# authentication-service.conf

name = "entra"
authorizeUrl = "https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/authorize"
accessTokenUrl = "https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/token"
clientId = "client-id-from-azure"
clientSecret = "client-secret-from-azure"
defaultScopes = ["openid", "profile", "email"]
forwardIssuerStateToAuthorizationServer = false

Auth0

# authentication-service.conf

name = "auth0"
authorizeUrl = "https://YOUR_DOMAIN.auth0.com/authorize"
accessTokenUrl = "https://YOUR_DOMAIN.auth0.com/oauth/token"
clientId = "client-id-from-auth0"
clientSecret = "client-secret-from-auth0"
defaultScopes = ["openid", "profile", "email"]
forwardIssuerStateToAuthorizationServer = false

Mapping ID Token Claims to Credentials

After successful authorization, the issuer receives an ID token with user claims. Use idTokenClaimsMapping in your credential profile to map those claims into credential fields.

See Issuer Profiles – ID Token Claim Mapping.

Last updated on July 1, 2026