Open ID Connect Support for AEM as a Cloud Service on Publish Tier open-id-connect-support-for-aem-as-a-cloud-service-on-publish-tier
Introduction introduction
As organizations modernize their digital experiences, secure and scalable identity management becomes a foundational requirement. Adobe Experience Manager (AEM) Cloud Service now supports OpenID Connect (OIDC) on the Publish tier, allowing seamless and standards-based integration with leading Identity Providers (IdPs) such as Entra ID (Azure AD), Google, Okta, Auth0, Ping Identity, ForgeRock and OIDC supported IDPs.
OIDC is an identity layer on top of the OAuth 2.0 protocol that enables robust user authentication while maintaining simplicity for developers. It is widely adopted for business-to-consumer (B2C), intranet, and partner portal scenarios, where secure user login and identity federations are required.
Until now, AEM customers were responsible for implementing their own custom login logic on the Publish tier, which increased development time and introduced long-term maintenance and security challenges. With native support for OIDC, AEM Cloud Service removes this burden by providing a secure, extensible, and Adobe-supported authentication mechanism for end users accessing Publish environments.
Whether you’re delivering a personalized consumer website or an authenticated internal portal, OIDC on Publish simplifies identity federation and reduces risk through centralized identity governance. It also helps organizations meet modern compliance and security standards without sacrificing agility.
Configure AEM for OIDC Authentication configure-aem-oidc-authentication
Prerequisites prerequisits
We assume that following information are available or defined:
- The paths of the content to be protected in the AEM repository
- An identifier for the IdP to be configured. This can be any string
Information from the IdP Configuration:
- The Client Id configured in the IdP
- The Client Secret configured in the Idp. If PKCE was configured on the Idp, the Client Secret is not available. Do not store the plain text value in the configuration file. Use a CM Secret and reference it
- The scopes configured on the Idp. At least the scope
openid
must be provided - Whether PKCE is enabled on the IdP
- The
callbackUrl
is defined using one of the configured path defined at point 1 and adding the suffix:/j_security_check
- The
baseUrl
to access to the standard.well-known
file. For example, if the well-known url is:https://login.microsoftonline.com/53279d7a-438f-41cd-a6a0-fdb09efc8891/v2.0/.well-known/openid-configuration
thebaseUrl
is:https://login.microsoftonline.com/53279d7a-438f-41cd-a6a0-fdb09efc8891
Overview of the Configuration Files overview-of-the-configuration-files
Find below a list of files that need to be configured:
- OIDC Connection: this will be used by the
OidcAuthenticationHandler
to authenticate the users, or by other components to authorize access to resources protected by the IdP using OAuth - OIDC Authentication Handler: This is the authentication handler used to authenticate users that access to the configured paths
- UserInfoProcessor: This component process the information received by the IdP. It can be extended by customers to implement custom logic
- Default Synchronization Handler: This component creates the user in the repository
- ExternalLoginModule: This component authenticate the user in the local oak repository.
The following diagram shows how the mentioned configuration elements are linked. Note that since these are ServiceFactory
components, the ~uniqueid
can be any random unique string:
Configure the OIDC Connection configure-the-oidc-connection
First, we need to configure the OIDC connection. Multiple OIDC connections can be configured, and each has to have a different name.
-
Create a new
.cfg.json
file that will house the configuration. For example, you can useorg.apache.sling.auth.oauth_client.impl.OidcConnectionImpl~azure.cfg.json
- the azure suffix must be a unique identifier for the connection -
Follow the configuration format in the example below:
code language-none { "name":"azure", "scopes":[ "openid" ], "baseUrl":"<https://login.microsoftonline.com/53279d7a-438f-41cd-a6a0-fdb09efc8891/v2.0>", "clientId":"5199fc45-8000-473e-ac63-989f1a78759f", "clientSecret":"xxxxxx" }
-
Configure the its properties as follows:
- The “name” can be defined by the user
baseUrl
,clientid
andclientSecret
are configuration values that come from the IdP.- The scopes must contain at least the value
openid
.
Configure OIDC Authentication Handler configure-oidc-authentication-handler
Now, configure the OIDC authentication handler. Multiple OIDC connections can be configured. Each has to have a different name. If they share the same OAK External Identity Provider, they can share users.
-
Create the configuration file. For this example, we’ll use
org.apache.sling.auth.oauth_client.impl.OidcConnectionImpl~azure.cfg.json
. Theazure
suffix must be a unique identifier. See an example of the configuration file below:code language-none { "path":"/content/tests/us/en/test-7", "callbackUri":"http://localhost:14503/content/tests/us/en/test-7/j_security_check", "pkceEnabled":false, "defaultConnectionName":"azure" "idp": "azure-idp" }
-
Then, configure its properties as follows:
path
: the path to be protectedcallbackUri
: to the path to be protected, adding the suffix:/j_security_check
defaultConnectionName
: configure with the same name defined for the OIDC connection on the previous step+pkceEnabled
:true
Proof Key for Code Exchange (PKCE) on Authorization code flowidp
: the name of the OAK External Identity Provider. Note that different OAK IDP cannot share users or groups
Configure SlingUserInfoProcessor
-
Create the configuration file. For this example, we’ll use
org.apache.sling.auth.oauth_client.impl.SlingUserInfoProcessor~azure.cfg.json
. Theazure
suffix must be a unique identifier. See an example of the configuration file below:code language-none { "groupsInIdToken":true, "groupsClaimName": "groups", "connection":"azure", "storeAccessToken": false, "storeRefreshToken": false }
-
Then, configure its properties as follows:
groupsInIdToken
: Set to true if the groups are sent in ID Token. If the value is false, or not specified, the groups are read from UserInfo endpoint.groupsClaimName
: Name of the claim contains the groups to be synchronized in AEM.connection
: configure with the same name defined for the OIDC connection on the previous stepstoreAccessToken
: true if the Access Token must be stored in the repostory. By default this is false. Set it to true only if AEM needs to access resources in behalf of the user stored in external servers protected by the same IdP.storeRefreshToken
: true if the Refresh Token must be stored in the repostory. By default this is false. Set it to true only if AEM needs to access resources in behalf of the user stored in external servers protected by the same IdP and need to refresh the token from the IdP.
Remark that Access Token and Refresh Token are stored encrypted with AEM master key.
Configure the Synchronization Handler configure-the-synchronization-handler
At least one Synchronization Handler must me configured to synchronize the users authenticated in oak. For more details, see this page.
Create a file named org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncHandler~azure.cfg.json
. The azure suffix must be a unique identifier. For more information on how to configure its properties, consult the Oak User and Group Synchronization documentation. Please find an example configuration below:
{
"user.expirationTime":"300s",
"user.membershipExpTime":"300s",
"user.propertyMapping":[
"profile/familyName=profile/familyName",
"profile/givenName=profile/givenName",
"rep:fullname=cn",
"profile/email=profile/email",
"oauth-tokens"
],
"user.pathPrefix":"azure",
"handler.name":"azure"
}
Below some of the most relevant attributes to be configured in DefaultSyncHandler. Remark that Dynamic Group Memberhsip should always be enabled in Cloud Services.
user.expirationTime
user.membershipExpTime
user.dynamicMembership
user.enforceDynamicMembership
group.dynamicGroups
UserInfoProcessor
synchronizes only few properties. It can be modified and customized.“profile/givenName=profile/given_name”,
“profile/familyName=profile/family_name”,
“rep:fullname=profile/name”,
“profile/email=profile/email”,
“access_token=access_token”,
“refresh_token=refresh_token”
user.membershipNestingDepth
Configure the External Login Module configure-the-external-login-module
Finally, you need to configure the External Login Module.
-
Create a file named
org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModuleFactory~azure.cfg.json
. See an example configuration below:code language-none { "sync.handlerName":"azure", "idp.name":"azure-idp" }
-
Configure its properties as follows:
sync.handlerName
: name of the Synchronization Handler defined previouslyidp.name
: OAK Identity Provider defined in OIDC Authentication Handler
Optional: Implement a Custom UserInfoProcessor implement-a-custom-userinfoprocessor
The user is authenticated by an ID Token, and additional attributes are fetched in the userInfo
endpoint defined for the IdP. If additional non-standard operations must be performed, a custom implementation of the UserInfoProcessor is the default implementation from Sling.
Example: Configure OIDC authentication with Azure Active Directory
Configure a new Application in Azure Active Directory configure-a-new-application-in-azure-ad
-
Create a new application in Azure Active Directory by following the Azure Active Directory documentation. See below how the screen detailing the application overview should look:
-
If Groups or application roles are required, follow the documentation to enable them for the application and send them in the ID Token. Below an example of configured groups:
-
Follow the previously documented steps to create the required configuration files. Below an example specific for Azure AD where:
- We define the name of oidc Connection, Authentication Handler and DefaultSyncHandler as:
azure
- The website url is:
www.mywebsite.com
- We protect the path
/content/wknd/us/en/adventures
- Tennant is:
tennat-id
, - Client id is:
client-id
, - Secret is:
secret
, - The groups are sent in the ID Token in a claim called:
groups
- We define the name of oidc Connection, Authentication Handler and DefaultSyncHandler as:
org.apache.sling.auth.oauth_client.impl.OidcConnectionImpl~azure.cfg.json
{
"name":"azure",
"scopes":[
openid", "User.Read", "profile", "email
],
"baseUrl":"https://login.microsoftonline.com/tenant-id/v2.0",
"clientId":"client-id",
"clientSecret":"secret"
}
org.apache.sling.auth.oauth_client.impl.OidcAuthenticationHandler~azure.cfg.json
{
"callbackUri":"https://www.mywebsite.com/content/wknd/us/en/adventures/j_security_check",
"path":[
"/content/wknd/us/en/adventures"
],
"idp":"azure",
"defaultConnectionName":"azure"
}
org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModuleFactory~azure.cfg.json
{
"sync.handlerName":"azure",
"idp.name":"azure"
}
org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncHandler~azure.cfg.json
{
"user.expirationTime":"1s",
"user.membershipExpTime":"1s",
"user.propertyMapping":[
"profile/givenName=profile/given_name",
"profile/familyName=profile/family_name",
"rep:fullname=profile/name",
"profile/email=profile/email",
"access_token=access_token",
"refresh_token=refresh_token"
],
"user.pathPrefix":"azure",
"group.pathPrefix": "oidc",
"user.membershipNestingDepth": "1",
"handler.name":"azure"
}
org.apache.sling.auth.oauth_client.impl.SlingUserInfoProcessorImpl~azure.cfg.json
{
"groupsInIdToken": "true",
"storeAccessToken": "false",
"storeRefreshToken": "false",
"connection": "azure",
"groupsClaimName": "groups"
}
Additional Information about Azure AD Groups additional-information-about-azure-ad-groups
To configure a group to for the enterprise application in the Microsoft Azure Portal, you need to search the application on: Enterprise Applications and add the groups:
To enable the group claim in Id Token, add the claim in the Token Configuration section of the Microsoft Azure Portal:
The configuration of SlingUserInfoProcessor
must be modified like in the example below.
The filaname that needs to be modified is org.apache.sling.auth.oauth_client.impl.SlingUserInfoProcessorImpl.cfg.json
. The content should be configured as follows:
{
"connection": "azure",
"groupsInIdToken": "true",
"storeAccessToken": "false",
"storeRefreshToken": "false"
}