Configuring single sign-on (SSO) for AEM Author instance with Okta using SAML is well documented and an easy to achieve task. However, when it comes to setup the same process on AEM Publish instance, there are a couple more steps one needs remember of - especially when it comes to setup scalable and (almost) stateless authentication process for publish farm. Generally speaking, AEM instance uses the SAML standard to exchange authentication and authorization data with the Okta service. It enables a web-based cross-domain single sign-on (SSO) and a single logout (SLO). The SAML standard defines AEM as Service Provider (SP) and Okta as Identity Provider (IdP).

SAML authentication process


Before we start the configuration process, there are two things we need to have ready:

  • Okta user with administrator rights,
  • AEM 6.5 instance.

Okta group and proper users assigned to it (users who should be able to log in AEM Publish instance using SSO) should be also configured. For the purpose of this tutorial, we already created "Okta Dev Visitors" (okta-dev-visitors) group with a couple of test users assigned.

To setup AEM instance we used Gradle AEM Multi-Project Example. The AEM environment consists of 1 Author and 2 Publish instances with Dispatcher in front of them. We will make use of the example domain and content that are available when using AEM Multi-Project Example.

Additionally, if you have more than one Publish instance, you will need to be capable of handling sticky sessions (e.g. by configuring a Load Balancing (LB) with sticky cookie).


This example config shows how to configure SSO for domain which is mapped to the /content/example/demo, so e.g.:

  • entering resolves to /content/example/demo/en-us.html.

1. Generate AEM keys and certificate

Generate and configure the AEM key pair (public certificate and private). Private key is used to sign SAML messages in Okta, while public key (certificate) is used to encrypt the message so only instance with that certificate can decrypt it, and to verify the signatures.

AEM configuration requires the private key in the PKCS8 format.

  1. Generate RSA private and public keys + certificate. To do this, run the following command and fill the form.
$ openssl req -x509 -sha256 -days 365 -newkey rsa:4096 -keyout aem.key -out aem.crt

pass: <password>
Country Name (2 letter code) [XX]:
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
  1. Convert PEM to DER format
openssl rsa -in aem.key -outform der -out aem.der
  1. Verify DER key
openssl rsa -in aem.der -inform der -text -noout
  1. DER key to PKCS8 - must be nocrypt, otherwise, AEM throws an error when adding the DER key:
openssl pkcs8 -topk8 -inform der -nocrypt -in aem.der -outform der -out aem-pkcs8.der

You should now have:

├── aem-pkcs8.der
├── aem.crt
├── aem.der
└── aem.key

2. Okta application

First, we need to create a new Okta application dedicated to AEM. The Okta application defines SSO/SLO integration details as well as users and permissions. A separate application is created for each environment (separate for author and publish).

2.1 Setup

Go to the admin panel: Select Applications -> Applications, click Add Application and then Create New App.

Choose Web and SAML 2.0.

Okta new app

2.2 Configuration

2.2.1 General settings

General settings

2.2.2 SAML settings
  1. Start with downloading Okta Certificate (its on the right-side panel): SAML Okta certificate
  2. General properties configuration

An authentication request from Okta to AEM first goes to https://PUBLISH_DOMAIN/<path configured in SAMLAuthenticationHandler OSGi config>/saml_login.

Audience URI (SP Entity ID) will be later used in the SAML Authentication Handler configuration. SAML settings

  1. Advanced settings configuration:

Click Show Advanced settings and fill the form according to the screenshot below. SAML settings

  1. Attributes configuration:

In this section, the user profile data sent in the AEM authentication request is configured. This section maps Okta user profile data to the response properties (e.g. email profile value will be sent in the field). We will make use of AEM SAML Authentication Handler and autocreate CRX Users after successful authentication basing on those attributes. Configure which fields should be part of this request. SAML settings

Finish and save the configuration.

2.2.3 Assign group to application

This step assumes that proper Group hierarchy exists in Okta (as mentioned in the Prerequisites).

In order to make successful authentication request to AEM, Okta application should have corresponding groups from Okta assigned (in our case it is Okta Dev Visitors group). These groups are part of the authentication request (filtered by the groupMembership attribute configured in the previous step). The corresponding groups must exist in the AEM instance (we will configure it in the AEM Group configuration step).

Open created app (Applications -> Applications and choose from the list). From Assignments tab choose Assign -> Assign to Groups. Find the proper group for the application and assign it: Okta app groups

2.2.4 Setup instructions
  1. Open created app (Applications -> Application and choose from the list). From the General tab copy Embed link for later.
  2. In the Sign On tab click View Setup Instructions and copy information for later.

Okta configuration is finished. You should now have:

  • okta.cert file downloaded
  • Embed link (aka IdP URL):
  • Single Logout URL:
  • name of the group for authenticated users: dev-okta-visitors

3. AEM configuration

These instructions are for Publish instance configuration. Each point should be executed separately on each AEM Publish instance unless stated otherwise. Some steps will be executed on the Author instance.

3.1 HMAC key synchronization

In order to make authentication mechanism stateless it is important to configure Encapsulated Token. Before you start any configuration - shut down all AEM publish instances in order to synchronize hmac key. When all instances are offline, follow the Replicating the HMAC key instructions from:

Since the instances are down, you don't have to restart any bundles. When all instances have the same hmac key, run them.

3.2 Trust store

Login to the AEM Publish instance (using https://AEM_PUBLISH_INSTANCE/libs/granite/core/content/login.html). Configure Okta certificate in the AEM trust store. Open https://AEM_PUBLISH_INSTANCE/libs/granite/security/content/truststore.html (or Tools -> Security -> Trust Store).

Create a Trust Store and Add Certificate from CER file. Upload okta.cert and submit. Write down Alias - it will be required later in SAML Authenticator Handler config.

Trust Store config

3.3 Authentication service

Configure authentication-service user Key Store with private key and certificate generated in step (1).

Open https://AEM_PUBLISH_INSTANCE/security/users.html (or Tools -> Security -> Users) and find authentication-service. Edit it and create new Keystore. Choose the new keystore alias and write it down for the later SAML Authenticator Handler config (in this example its local-publish-alias).

Authentication service keystore

3.4 SAML Authentication Handler

Configure the AEM SAML Authentication Handler to enable SAML authentication and authorization. Open OSGi Config Manager: https://AEM_PUBLISH_INSTANCE/system/console/configMgr and find Adobe Granite SAML 2.0 Authentication Handler config and create a new configuration with the following settings:


  • Path is configured for the root page before AEM mapping is done. Remember that Okta SAML general settings Single sign on URL should correspond to the path configured here.
  • IDP URL is the Embed link copied from the Okta Setup instructions.
  • IDB Certificate Alias is the alias of configured Trust Store.
  • Service Provider Entity ID is the one configured in Okta SAML Settings in Audience URI (SP Entity ID).
  • SP Private Key Alias is authentication-service keystore alias
  • Password of Key Store - authentication-service keystore password

AEM can automatically create users upon first login and assign them to valid groups based on the Okta authentication response. It is configured in the SAML Authentication Handler Configuration.

  • Group Membership - Okta Group Attribute
  • Default Group - default AEM group
  • Synchronized Attributes - mapping of attributes from Okta SAML request to AEM user profile.

Configure also Single Logout: SAML SLO

Optionally you may configure a separate Logger for SAML:

3.5 Apache Sling Referrer Filter

Configure the Apache Sling Referrer Filter. Open OSGi Config Manager: https://AEM_PUBLISH_INSTANCE/system/console/configMgr, find Apache Sling Referrer Filter and edit it. Specify Okta domain and host regexp:

Sling Referrer Filter

3.6 Sling Authenticator

In order to enforce login at a specific path or URI, we need to add a new authentication requirement in the Sling Authentication Service. In our case it is:, because we use two way mappings (in the /etc/map.publish/http/

AEM Demo mappings

That means in this particular case we can't specify the path.

When path rewriting is handled by the Apache mod_rewrite, it would be possible to configure authentication requirement as a path. In that case, this step can be replaced by creating a service that will provide a "sling.auth.requirements" property with the path value.

We need to configure it in the Sling Authentication Service by adding new authentication requirements.

Authentication service config

Read more on this here:

3.7 User group for authenticated users

In order to authorize authenticated users, a group with proper rights for that user has to exist on Publish instance. Now we will create a group that has access to the /content/example/demo. It is important that group has exactly the same path in JCR on all AEM Publish instances. It is recommended to create the group on Author instance and replicate it to all Publish instances. If the group will be created separately on each Publish instance, Users synchronization with Sling Distribution will not work properly.

Add a new group that name corresponds to the name from the Okta SAML request. Open https://AEM_AUTHOR/security/groups.html (or Tools -> Security -> Groups) and add a new group.

New group

Now add proper rights and activate the group so it will be replicated to all Publish instances under the same JCR path /home/groups/....

You should now be able to authenticate to AEM Publish using your Okta user (assuming it is assigned to the Okta Application and Okta Group that is connected with this AEM instance).

3.8 Token Authentication Handler

The default authentication token is persisted in the repository under user's profile. That means the authentication mechanism is stateful. Encapsulated Token is the way to configure stateless authentication. It ensures that the cookie can be validated without having to access the repository.

Open OSGi Config Manager: https://AEM_PUBLISH_INSTANCE/system/console/configMgr, find Adobe Granite Token Authentication Handler and edit it:

  • tick the Enable encapsulated token support box and press Save

3.9 Sling Distribution users synchronization

As mentioned in Encapsulated token documentation:

Please note that the Encapsulated Token is about authentication. It ensures that the cookie can be validated without having to access the repository. However, it is still required that the user exists on all the instances and that the information stored under that user can be accessed by every instance.

For example, if a new user is created on publish instance number one, due to the way the Encapsulated Token works, it will be authenticated successfully on publish number two. If the user does not exist on the second publish instance, the request will still not be successful.

3.9.1 Sync Agents Factory configuration on AEM Author

On Author instance open the OSGi Config Manager: https://AEM_AUTHOR_INSTANCE/system/console/configMgr, find the Apache Sling Distribution Agent - Sync Agents Factory and edit socialpubsync config (verify that Name is socialpubsync):

  • tick the Enabled checkbox,
  • For each Publish instance in the farm, configure Exporter Endpoinds and Importer Endpoints

Sync Agents Factory AEM Author config Save all the changes.

3.9.2 Create authorized user

Sign in with administrator privileges to Publish instance and open the user admin: https://AEM_PUBLISH_INSTANCE/useradmin. Create a new user, e.g. usersync-admin, remember the password and add this user to the Administrators group. Remember to have exactly the same user with exactly the same password configured on each Publish instance.

3.9.3 Configure authorized user permissions

For the created usersync-admin user, add the Allow jcr:all ACL with the restriction rep:glob=*/activities/*. In order to do that, access the CRXDE Lite https://AEM_PUBLISH_INSTANCE/crx/de with administrator privileges and select the /home node. In the right pane, select the Access Control tab and add ACL entry with + icon. Fill the form and Save All changes.

Authorized user ACL config

3.9.4 Apache Sling Distribution Transport Credentials configuration on AEM Author

On Author instance open the OSGi Config Manager: https://AEM_AUTHOR_INSTANCE/system/console/configMgr, locate the Apache Sling Distribution Transport Credentials - User Credentials based DistributionTransportSecretProvider and create select existing (or create a new one) configuration for socialpubsync-publishUser.

Apache Sling Distribution Transport Credentials

The Password is the one configured for the user in the 3.9.2 Create authorized user point.

3.9.5 Apache Sling Distribution Agent configuration

On Publish instance open the OSGi Config Manager: https://AEM_PUBLISH_INSTANCE/system/console/configMgr, find the Apache Sling Distribution Agent - Queue Agents Factory and edit the existing socialpubsync-reverse config:

  • tick the Enabled checkbox and press Save.
3.9.6 Diff Observer Factory config

On Publish instance open the OSGi Config Manager: https://AEM_PUBLISH_INSTANCE/system/console/configMgr, find the Adobe Social Sync - Diff Observer Factory and edit the existing socialpubsync-reverse config:

  • tick the Enabled checkbox and press Save.
Additional steps

Detailed instructions, optional steps (like Apache Sling Distribution Trigger configuration) and troubleshooting on users and groups synchronization with Sling Distribution can be found in the Adobe docs:

In order to keep the freshly-authenticated user tied to the AEM Publish instance for a short period (just to let Sling Distribution synchronize users and groups), a Sticky Cookie should be added to the response of SAML authentication (the one to /en-us/saml_login). To do that, a rewrite rule on Apache server can be used:

  RewriteRule "^.*/saml_login$" "-" [E=SAML_LOGIN_REQUEST:1]
  Header add Set-Cookie "Instance=1;; Path=/; Max-Age=60" env=SAML_LOGIN_REQUEST

Now, use that cookie as a base for Sticky Cookie generation in your Load Balancer. That will keep the user tied to the AEM instance where the user profile was generated long enough to distribute her or his profile amongst all Publish instances.


Through this tutorial we configured AEM Publish farm with SSO. The solution is scalable (can support any number of AEM Publish instances in farm) thanks to Encapsulated Token stateless characteristics and short-lived sticky cookie (just to let user data sync on all Publish instances).