arrow-down
  1. Usage
  2. Configuration
  3. Examples

Configuration

Contents

The application is configured via a file called com.enonic.app.oidcidprovider.cfg, using the properties format.

Since the configuration is extensive, documentation has been broken down into several sections below. All available configuration options listed here.

General

Enonic uses ID providers to provide auth for various endpoints such as Admin/websites and APIs. This application may back multiple ID providers, meaning you may for instance support Google, Entra, and Auth0 - and even multiple ID providers for a single OIDC service.

As such, most properties are prefixed with a named ID Provider i.e. idprovider.[idprovidername].[configkey] = [value], where idprovidername is a unique name matching the ID provider in Enonic XP.

For ease of reading we omit the idprovider.<name>. prefix in most of the documentation below. See the examples for a complete setup.

ID provider setup

The application can automatically initialize, one or more ID providers using the following configuration fields:

com.enonic.app.oidcidprovider.cfg
# ID provider setup
autoinit=(true|false) (1)
idprovider.<name>.displayName=(string, optional) (2)
idprovider.<name>.description=(string, optional) (3)
1 When true, each id provider declared by <name> in this configuration file will automatically be created in Enonic XP
2 Optionally provide a "pretty" name for the ID provider
3 Optional description for the ID provider

Client

The Client parameters are mandatory for the Authorization Code Flow, but not used for Auto Login.You can obtain these values from your 3rd party OIDC server, like Google or Auth0 when creating a client/application there.

com.enonic.app.oidcidprovider.cfg
# Client
clientId=(string) (1)
clientSecret=(space separated strings) (2)
method=(post|basic|jwt)(3)
usePkce=(true|false) (4)
1 Client ID you obtain from your OIDC server
2 Client Secret you obtain from your OIDC server. A space-separated list of secrets used for rotation. The new secret can be added as a fallback to the old one.
3 Optionally specify the method for how client ID and client secret will be passed to the OIDC server. The values correspond to client_secret_basic, client_secret_post and private_key_jwt methods, respectively.
4 usePkce - If set to false, the app will not use PKCE for the Authorization Code Flow.
You may disable Authorization Code Flow by omitting clientId in your configuration

Authorization server

These values can be obtained from your OIDC server when registering a new Client/application.

com.enonic.app.oidcidprovider.cfg
# Authorization server
oidcWellKnownEndpoint=(string) (1)
issuer=(string)
authorizationUrl=(string)
tokenUrl=(string)
userinfoUrl=(string) (2)
jwksUri=(string) (3)
1 When oidcWellKnownEndpoint is set, the values for issuer, authorizationUrl, tokenUrl, userinfoUrl and jwksUri will automatically be fetched from the well-known endpoint - and you do not need to fill them in.

Your OIDC provider may only offer an Issuer URL. Then, the URLs are likely accessible under [Issuer URL]/.well-known/openid-configuration

Examples of OpenID Connect Discovery URL:

2 userinfoUrl if provided, the app will use this URL to retrieve the user claims to create/update the User in Enonic. (When useUserinfo is set to false this value is not used)
3 jwksUri - JSON Web Key Set (JWKS) - The app will use this URL to retrieve the public keys used to verify the signature of the Bearer Token during Auto Login, and ID Token in the Auth Code Flow. For Autologin flow, this property must exist.

Rules

Additional rules enforced on user creation

com.enonic.app.oidcidprovider.cfg
# Rules
rules.forceEmailVerification=(true|false, required) (1)
1 When rules.forceEmailVerification is true the claim email_verified (returned with the scope email) must exist.

User mappings

This section describes how users are mapped from OIDC to Enonic.

For Authorization Code Flow, user data are synched with Enonic on every login. The user’s displayName and email will be updated from the same sources as for user creation.
com.enonic.app.oidcidprovider.cfg
# User mappings
useUserinfo=(true|false) (1)
claimUsername=(string, optional, defaults to "sub") (2)
scopes=(space separated strings, defaults to "profile email") (3)
mappings.displayName=(string, required, defaults to @@{userinfo.preferred_username}) (4)
mappings.email=(string, required, defaults to @@{userinfo.email}) (5)
defaultGroups=(space separated group keys) (6)
1 When useUserinfo is set to false the claims from userinfoUrl will be ignored, and you must specify your own claims below.
2 Set this if useUserinfo is false.claimUsername is important, as this represents the unique identifier that will keep the Enonic user and the OIDC user in sync. For instance, OIDC uses sub as a unique, unchanging user identifier, and in Microsoft Entra this comes from the user’s oid.
3 Set this if useUserinfo is false. Defines which scopes to fetch from the OIDC server.
4 Template for the displayName uses the format @@{expression}, e.g. @@{userinfo.preferred_username}
5 email mapping uses @@{expression} format, e.g. @@{userinfo.email}
6 defaultGroups makes all users member of the specified Enonic groups. The group name must be in the format group:[idprovidername]:[groupname], e.g. group:myidprovider:authors

Groups from claim

While defaultGroups only applies at user-creation time, this feature keeps a user’s Enonic group memberships in sync with a claim in the OIDC token on every login. The IdP supplies a list of groups/roles in a claim, and a mapping table translates each claim value into an Enonic group key.

The feature is disabled by default. Presence of groups.claim is what enables it. Existing configurations are unaffected.
com.enonic.app.oidcidprovider.cfg
# Groups from claim
groups.claim=(string, optional) (1)
groups.mapping.0.value=(string, required) (2)
groups.mapping.0.group=(string, required) (3)
groups.syncMode=(add|sync, optional, defaults to "add") (4)
1 groups.claim is the path to the groups claim in the merged claims object. If the value contains : (a URI scheme or URN, e.g. https://app.example.com/groups) it is treated as a single literal key. Otherwise it is split on . as a dotted path, e.g. groups or realm_access.roles. The feature is disabled when this property is absent or empty.
2 value is the literal value as it appears in the OIDC claim array. It is compared with strict, case-sensitive equality.
3 group is the Enonic group key the value maps to. It must be in the format group:[idprovidername]:[groupname] and must reference this ID provider. Cross-IDP keys are rejected. Values not listed in the mapping are ignored.
4 syncMode controls revocation. add only adds the user to mapped groups present in the claim. sync additionally removes the user from mapped groups not present in the claim. Only groups that appear in this mapping are ever touched — manual memberships, defaultGroups, and groups managed elsewhere are preserved.
For multiple groups, add more lines and iterate the array counter (groups.mapping.1.value, groups.mapping.1.group, …​).
Groups referenced by the mapping are created automatically when the application starts and whenever its configuration file changes (which restarts the app) — not lazily on first login. So a mapped group is available in the admin Users app for permission setup right away, before anyone logs in. Eager creation requires autoinit=true (the same flag that auto-creates the ID providers themselves); if a mapped group is still missing at login it is skipped with a warning.

Choosing the claim for your provider

Provider Typical groups.claim

Okta

groups (add the groups scope and a claim with a filter in a custom Authorization Server)

Microsoft Entra ID

groups (configured via groupMembershipClaims in the app manifest; values are GUIDs by default, so map each GUID to a group key)

Auth0

a namespaced URI set by a post-login Action, e.g. https://app.example.com/groups

Keycloak

realm_access.roles (built-in), or groups with a Group Membership mapper

Microsoft Entra emits a "groups overage" indirection instead of the group list for users in more than 200 groups. Resolving it requires a Graph API call and is not handled by this app; such tokens result in no group changes.

Handling group rot

Over time, groups referenced by old mappings or memberships granted from claims that no longer apply can accumulate ("group rot"). There are two strategies:

  • syncMode=add (default) plus periodic out-of-band cleanup — safest; the app never revokes memberships.

  • syncMode=sync — OIDC becomes authoritative for the mapped groups, and stale memberships are removed automatically on the next login. Sync mode only ever touches groups that appear in the mapping, so it is safe to enable without affecting manually-assigned or default groups.

Additional endpoints

You may optionally specify additional Endpoints to fetch and store more user data in the Enonic user profile.

com.enonic.app.oidcidprovider.cfg
# Additional Endpoints
additionalEndpoints.0.name=(string, required) (1)
additionalEndpoints.0.url=(string, required)
1 name must be a unique string that will be mapped to a scope within the Enonic user profile, where the values will be stored.
For multiple endpoints, simply add more lines, and iterate the array counter.

Autologin

Autologin is a concept in Enonic XP, where every request (without an existing session) may automatically be logged in. This is for instance useful if you want to support authentication for an API, rather than a regular website.

This application supports automatically logging in users when the client passes a special header: Authorization: Bearer <token> - The token must be a valid JWT for your ID provider.

To enable Autologin, you need to specify the jwksUri in the ID Provider configuration or oidcWellKnownEndpoint that ID Provider uses to obtain the value for the jwksUri automatically.
com.enonic.app.oidcidprovider.cfg
# Autologin
autoLogin.createUser=(true|false) (1)
autoLogin.createSession=(false|true) (2)
autoLogin.wsHeader=(false|true) (3)
autoLogin.allowedAudience=(space separated strings) (4)
autoLogin.applyGroups=(true|false, defaults to false) (5)
1 If you disable 'createUser', the user will be logged in, but not persisted as a user within Enonic. If true, a user will be created automatically if it doesn’t exist.
2 Optionally create a session in Enonic when the user is logged in. By default, the user will be logged in with REQUEST scope.
3 ID provider will look for a token in the Sec-WebSocket-Protocol header.
4 allowedAudience is a list of space-separated strings. If set, the app will only accept tokens with an audience that matches one of the values in this list. It is highly recommended to set this value to make sure the correct tokens are used for the auto login.
5 When true, also apply groups from claim sync during Bearer autoLogin. The claim is resolved against the raw JWT payload (no userinfo endpoint is called).

endSession

OpenID Connect Front-Channel Logout is optional and might not be supported by your authentication server. You can check if the endpoint is available in the OpenID Configuration (.well-known/openid-configuration) under the field end_session_endpoint. There might also be another custom endpoint available that achieves the same purpose. The ID Provider Configuration schema tries to be dynamic enough to handle all cases.

When oidcWellKnownEndpoint is configured and the well-known configuration contains an end_session_endpoint, the application will automatically use it — no explicit endSession.url configuration is needed.

com.enonic.app.oidcidprovider.cfg
# EndSession
endSession.url=(string) (1)
endSession.idTokenHintKey=(string) (2)
endSession.postLogoutRedirectUriKey=(string) (3)
endSession.additionalParameters.0.key=(string)
endSession.additionalParameters.0.value=(string)
1 url: should contain the value of end_session_endpoint in your OpenID Provider. Required unless oidcWellKnownEndpoint is set and the well-known configuration includes end_session_endpoint.
2 idTokenHintKey should optionally set the id_token_hint for your OpenID Provider
3 postLogoutRedirectUriKey optionally set the post_logout_redirect_uri in your OpenID Provider

Example values

Auth0
  • End Session URL: https://YOUR_AUTH0_DOMAIN/v2/logout

  • Post Logout Redirect URI parameter name: returnTo

  • Additional Parameters:

    • clientId = [Client ID]

Google

Not available

Microsoft Entra
ID-porten
  • End Session URL: https://login.idporten.no/logout

  • ID Token Hint parameter name: id_token_hint

  • Post Logout Redirect URI parameter name: post_logout_redirect_uri

User Events

com.enonic.app.oidcidprovider.cfg
userEventPrefix=(string, optional, defaults to "app.name")  (1)
userEventMode=(off|local|distributed, optional, defaults to "local")  (2)
1 userEventPrefix is used to customize the type of user events such as login, create, and modify. By default, the application name is used as the prefix. For instance, the login event will look like <userEventPrefix>.user.login. To listen for this event, use custom.<userEventPrefix>.user.login.
2 userEventMode allows you to disable user events or specify whether they should be distributed in the cluster or locally.

All options

All available configuration options

com.enonic.app.oidcidprovider.cfg:
# IDprovider setup
autoinit=(true | false)
idprovider.<name>.displayName=(string)
idprovider.<name>.description=(string)

# Client
idprovider.<name>.clientId=(string)
idprovider.<name>.clientSecret=(string)
idprovider.<name>.method=(post|basic|jwt)

# Authorization server
idprovider.<name>.oidcWellKnownEndpoint=(string)
idprovider.<name>.issuer=(string)
idprovider.<name>.authorizationUrl=(string)
idprovider.<name>.tokenUrl=(string)
idprovider.<name>.userinfoUrl=(string)
idprovider.<name>.jwksUri=(string)
idprovider.<name>.usePkce=(true|false)

# Rules
idprovider.<name>.rules.forceEmailVerification=(true|false)

# User mappings
idprovider.<name>.useUserinfo=(true|false)
idprovider.<name>.claimUsername=(string)
idprovider.<name>.scopes=(space separated strings, defaults to "profile email")
idprovider.<name>.mappings.displayName=(string, required, defaults to @@{userinfo.preferred_username})
idprovider.<name>.mappings.email=(string, required, defaults to @@{userinfo.email})
idprovider.<name>.defaultGroups=(space separated group keys)

# Groups from claim
idprovider.<name>.groups.claim=(string)
idprovider.<name>.groups.mapping.0.value=(string, required)
idprovider.<name>.groups.mapping.0.group=(string, required)
idprovider.<name>.groups.syncMode=(add|sync, defaults to "add")

# Additional Endpoints
idprovider.<name>.additionalEndpoints.0.name=(string, required)
idprovider.<name>.additionalEndpoints.0.url=(string, required)

# Autologin
idprovider.<name>.autoLogin.createUser=(true|false)
idprovider.<name>.autoLogin.createSession=(true|false)
idprovider.<name>.autoLogin.wsHeader=(false|true)
idprovider.<name>.autoLogin.allowedAudience=(space separated strings)
idprovider.<name>.autoLogin.applyGroups=(true|false, defaults to false)

# User Events
idprovider.<name>.userEventPrefix=(string, defaults to the current application name)
idprovider.<name>.userEventMode=(off|local|distributed, defaults to 'local')

# EndSession
idprovider.<name>.endSession.url=(string)
idprovider.<name>.endSession.idTokenHintKey=(string)
idprovider.<name>.endSession.postLogoutRedirectUriKey=(string)
idprovider.<name>.endSession.additionalParameters.0.key=(string, required)
idprovider.<name>.endSession.additionalParameters.0.value=(string, required)

Contents

Contents