Service credentials

Integrations with Adobe Experience Manager (AEM) as a Cloud Service must be able to securely authenticate to AEM service. AEM’s Developer Console grants access to Service Credentials, which are used to facilitate external applications, systems and services to programmatically interact with AEM Author or Publish services over HTTP.

AEM integrates with other Adobe products using S2S OAuth managed via the Adobe Developer Console. For custom integrations with service accounts, JWT credentials are used and managed in the AEM Developer Console.

Transcript
Now let’s take a look at service credentials which are the real credentials an external app will use to programmatically access AEM. On the service, local development access tokens, and service credentials seem similar as they both are used by external applications to programmatically access specific aims of cloud service environments, author or published services, and they’re obtained for specific environment through its developer console. The major difference is that service credentials are actual static credentials rather than an access token. Service credentials themselves are not directly sent to AEM to be authenticated. Instead, the external application uses these to generate a JWT, which is exchange with Adobe IMS for an access token, which can then be used to authenticate http requests to aim as a cloud service. So let’s take a look at how we can obtain, and use service credentials. We’ll head over to the AEM developers console, tap the integrations tab, and then select the technical accounts tab.
This tab lists any technical accounts associated with the selected AEM environment. You can think of technical accounts as the service user that the service credentials will authenticate to AEM as. The technical accounts eventually manifest in AEM as AEM users, which can then be permissioned. Also, if credentials for a specific technical account are compromised, they can be revoked without affecting other consumers.
So let’s go ahead and create a new technical account. This takes a few seconds, but when it’s done, we’re presented with the service credentials JSON object.
We’ll download this and use it in our app in a few moments. Notice that these are bonafide credentials, even containing a private key. These credentials should be stored, managed, and accessed in accordance with your organization’s IT security policy.
Before we jump back to our external app, let’s close this window, and check out the developer console again.
We can see that our new technical account is listed with each of its private keys associated with it listed below.
If we need to retrieve the service credentials again, simply expand the current private key, and then select view next to the active certificate entry.
Do note that a private key can have multiple active certificates which is very useful when updating expiring credentials. So what I mean by this is you can keep an expiring credential active, and then create a new certificate which will by default be active for a year.
Take the credentials from the new certificate, and update your app with them, and then revoke the expiring certificate resulting in zero service interruption.
Before we jump back to our external app, it’s worth noting that in order to remove a technical account, you must revoke and delete all certificates associated with the technical account. Only then will the delete option on the technical account drop down become available.
Okay, enough with the developer console, let’s head back and use our service credentials, and our external application.
For convenience, I’ll copy them from the downloads folder to my project folder. But remember, don’t check these index.js since they are credentials.
Then let’s update the application to handle either local development access token, JSON or service credential JSON. It’s nice to think about designing your application to handle switching between both, so significant code changes don’t need to be made between local development and real life production use. And the get access function will add an else condition to handle the case when service credential JSON is provided. Then we’ll need to do two things. One, generate a JWT using the information in the service credentials and two, exchange the JWT with the Adobe IMS API’s for an access token, we can then use with our http request to AEM. Since this is a node.js application, the easiest and best way to facilitate this is using Adobe’s JWT OAuth and PM module, which takes the config object comprised of select data from the service credentials, and exchanges it with Adobe IMS for an access token to AEM. This MPI module conveniently abstracts all this away into a single function call. If you’re using another programming language, or want to review the inner workings of the JWT construction and exchange with IMS, see the other sample code links provided below on this page.
With our new code in place, the rest of our application should work as normal. Passing the access token on the http request to AEM as a bare token and the authorization http header.
Okay, now let’s turn our application from the command line using the service credentials. This looks like the command line used to execute with the local develop access token JSON.
However, I’ll specify a new property value, so we can tell if the service credential base update works, and in the file prem, I’ll point to the JSON containing the service credentials downloaded from AEM developer console.
Running command, we see the first http request which reads the list of assets in the folder succeeds. However, the following request for metadata update of each asset fails. So why did this fail here, but not with the local development access token? The reason is the local development access token authenticates the request as the user who generated it, and my user is in the AEM administrator’s group meaning it as full read and write access to AEM, service credentials, on the other hand, authenticate to AEM as a discrete technical account user that is part of the AEM user’s access profile, meaning by default it only has read access. So this is why the read operation listing the assets succeeded; however, the update of the assets which is a write operation failed.
We can see and resolve this by heading over to AEM as the cloud services, tools, security, users.
At the top of the list, we see our technical account user whose login name maps to the email field in the service credentials JSON, and was loosely created upon first access using these service credentials generated access token.
Opening this user, we see it’s a member of the contributors AEM group which only provides read access to AEM. We can adjust this technical account user’s permissions in the usual manner in AEM. So for simplicity, let’s add it to the DAM User’s group, which provides right access to AEM. We’ll save our changes, and then head back and rerun the application.
And there we go, all our http requests appear to be successful. We’ll jump back to AEM, so we can check to see if our assets metadata has indeed been updated with a new property value.
And there we go, it has been. -

Service Credentials may appear similar Local Development Access Tokens but are different in a few key ways:

  • Service Credentials are associated with Technical Accounts. Multiple service credentials can be active for a Technical Account.
  • Service Credentials are not access tokens, rather they are credentials that are used to obtain access tokens.
  • Service Credentials are more permanent (their certificate’s expire every 365 days), and do not change unless revoked, whereas Local Development Access Tokens expire daily.
  • Service Credentials for an AEM as a Cloud Service environment map to a single AEM technical account user, whereas Local Development Access Tokens authenticate as the AEM user who generated the access token.
  • An AEM as a Cloud Service environment can have up to ten technical accounts, each with their own Service Credentials, each mapping to discrete technical account AEM user.

Both Service Credentials and the access tokens they generate, and Local Development Access Tokens, should be kept secret. As all three can be used to obtain, access to their respective AEM as a Cloud Service environment.

Generate Service Credentials

Service Credentials generation is broken into two steps:

  1. A one-time Technical Account creation by an Adobe IMS Org administrator
  2. The download and use of the Technical Account’s Service Credentials JSON

Create a Technical Account

Service Credentials, unlike Local Development Access Tokens, require a Technical Account to be created by an Adobe Org IMS Administrator before they can be downloaded. Discrete Technical Accounts should be created for each client that requires programmatic access to AEM.

Create a Technical Account

Technical Accounts are created once, however the Private Keys uses to manage Service Credentials associated with the Technical Account can be managed over time. For example, new Private Key/Service Credentials must be generated prior to the current Private Key’s expiration, to allow for uninterrupted access by a user of the Service Credentials.

  1. Ensure you are logged in as a:

    • Adobe IMS Org’s System Administrator
    • Member of the AEM Administrators IMS Product Profile on AEM Author
  2. Log in to Adobe Cloud Manager

  3. Open the Program containing the AEM as a Cloud Service environment to integrate set up the Service Credentials for

  4. Tap the ellipsis next to the environment in the Environments section, and select Developer Console

  5. Tap in the Integrations tab

  6. Tap the Technical Accounts tab

  7. Tap Create new technical account button

  8. The Technical Account’s Service Credentials are initialized and displayed as JSON

AEM Developer Console - Integrations - Get Service Credentials

Once the AEM as Cloud Service environment’s Service Credentials have been initialized, other AEM developers in your Adobe IMS Org can download them.

Download Service Credentials

Download Service Credentials

Downloading the Service Credentials follows the similar steps as the initialization.

  1. Ensure you are logged in as a:

    • Adobe IMS Org’s Administrator
    • Member of the AEM Administrators IMS Product Profile on AEM Author
  2. Log in to Adobe Cloud Manager

  3. Open the Program containing the AEM as a Cloud Service environment to integrate with

  4. Tap the ellipsis next to the environment in the Environments section, and select Developer Console

  5. Tap in the Integrations tab

  6. Tap the Technical Accounts tab

  7. Expand the Technical Account to be used

  8. Expand the Private Key whose Service Credentials will be downloaded, and verify that the status is Active

  9. Tap on the > View associated with the Private Key, which displays the Service Credentials JSON

  10. Tap on the download button in the top-left corner to download the JSON file containing the Service Credentials value, and save the file to a safe location

Install the Service Credentials

The Service Credentials provide the details needed to generate a JWT, which is exchanged for an access token used to authenticate with AEM as a Cloud Service. The Service Credentials must be stored in a secure location accessible by the external applications, systems, or services that use it to access AEM. How and where the Service Credentials are managed are unique per customer.

For simplicity, this tutorial passes the Service Credentials in via the command line. However, work with your IT Security team to understand how to store and access these credentials in accordance with your organization’s security guidelines.

  1. Copy the downloaded the Service Credentials JSON to a file named service_token.json in the root of the project
    • Remember, never commit any credentials to Git!

Use Service Credentials

The Service Credentials, a fully formed JSON object, are not the same as the JWT nor the access token. Instead the Service Credentials (which contain a private key), are used to generate a JWT, which is exchanged with Adobe IMS APIs for an access token.

Service Credentials - External Application

  1. Download the Service Credentials from AEM Developer Console to a secure location
  2. The External Application needs to programmatically interact with AEM as a Cloud Service environment
  3. The External Application reads in the Service Credentials from a secure location
  4. The External Application uses information from the Service Credentials to construct a JWT Token
  5. The JWT Token is sent to Adobe IMS to exchange for an access token
  6. Adobe IMS returns an access token that can be used to access AEM as a Cloud Service
    • Access tokens can not change an expiry time.
  7. The External Application makes HTTP requests to AEM as a Cloud Service, adding the access token as a Bearer token to the HTTP requests’ Authorization header
  8. AEM as a Cloud Service receives the HTTP request, authenticates the request, and performs the work requested by the HTTP request, and returns an HTTP response back to the External Application

Updates to the External Application

To access AEM as a Cloud Service using the Service Credentials, the external application must be updated in three ways:

  1. Read in the Service Credentials
  • For simplicity, the Service Credentials are read from the downloaded JSON file, however in real-use scenarios, Service Credentials must be securely stored in accordance to your organization’s security guidelines
  1. Generate a JWT from the Service Credentials
  2. Exchange the JWT for an access token
  • When Service Credentials are present, the external application uses this access token instead of the Local Development Access Token, when accessing AEM as a Cloud Service

In this tutorial, Adobe’s @adobe/jwt-auth npm module is used to both, (1) generate the JWT from the Service Credentials, and (2) exchange it for an access token, in a single function call. If your application is not JavaScript based, please review the sample code in other languages for how to create a JWT from the Service Credentials, and exchange it for an access token with Adobe IMS.

Read the Service Credentials

Review the getCommandLineParams() so see how the Service Credentials JSON file is read using the same code used to read in the Local Development Access Token JSON.

function getCommandLineParams() {
    ...

    // Read in the credentials from the provided JSON file
    // Since both the Local Development Access Token and Service Credentials files are JSON, this same approach can be re-used
    if (parameters.file) {
        parameters.developerConsoleCredentials = JSON.parse(fs.readFileSync(parameters.file));
    }

    ...
    return parameters;
}

Create a JWT and exchange for an Access Token

Once the Service Credentials are read, they are used to generate a JWT which is then exchanged with Adobe IMS APIs for an access token. This access token can then be used to access AEM as a Cloud Service.

This example application is Node.js-based, so it’s best to use @adobe/jwt-auth npm module to facilitate the (1) JWT generation and (20 exchange with Adobe IMS. If your application is developed using another language, please review the appropriate code samples on how to construct the HTTP request to Adobe IMS using other programming languages.

  1. Update the getAccessToken(..) to inspect the JSON file contents and determine if it represents a Local Development Access Token or Service Credentials. This can be easily achieved by checking for the existence of the .accessToken property, which only exists for Local Development Access Token JSON.

    If Service Credentials are provided, the application generates a JWT and exchanges it with Adobe IMS for an access token. Use the @adobe/jwt-auth’s auth(...) function which generates a JWT and exchanges it for an access token in a single function call. The parameters to auth(..) method are a JSON object comprised of specific information available from the Service Credentials JSON, as described below in code.


 async function getAccessToken(developerConsoleCredentials) {

     if (developerConsoleCredentials.accessToken) {
         // This is a Local Development access token
         return developerConsoleCredentials.accessToken;
     } else {
         // This is the Service Credentials JSON object that must be exchanged with Adobe IMS for an access token
         let serviceCredentials = developerConsoleCredentials.integration;

         // Use the @adobe/jwt-auth library to pass the service credentials generated a JWT and exchange that with Adobe IMS for an access token.
         // If other programming languages are used, please see these code samples: https://www.adobe.io/authentication/auth-methods.html#!AdobeDocs/adobeio-auth/master/JWT/samples/samples.md
         let { access_token } = await auth({
             clientId: serviceCredentials.technicalAccount.clientId, // Client Id
             technicalAccountId: serviceCredentials.id,              // Technical Account Id
             orgId: serviceCredentials.org,                          // Adobe IMS Org Id
             clientSecret: serviceCredentials.technicalAccount.clientSecret, // Client Secret
             privateKey: serviceCredentials.privateKey,              // Private Key to sign the JWT
             metaScopes: serviceCredentials.metascopes.split(','),   // Meta Scopes defining level of access the access token should provide
             ims: `https://${serviceCredentials.imsEndpoint}`,       // IMS endpoint used to obtain the access token from
         });

         return access_token;
     }
 }
Now, depending on which JSON file - either the Local Development Access Token JSON or the Service Credentials JSON - is passed in via tha `file` command line parameter, the application will derive an access token.

Remember, that while the Service Credentials expire every 365 days, the JWT and corresponding access token expire frequently, and need to be refreshed before they expire. This can be done by using a `refresh_token` [provided by Adobe IMS](https://www.adobe.io/authentication/auth-methods.html#!AdobeDocs/adobeio-auth/master/OAuth/OAuth.md#access-tokens).
  1. With these changes in place, the Service Credentials JSON was downloaded from the AEM Developer Console and for simplicity, saved as service_token.json in the same folder as this index.js. Now, let’s execute the application replacing the command-line parameter file with service_token.json, and updating the propertyValue to a new value so the effects are apparent in AEM.

    code language-shell
    $ node index.js \
        aem=https://author-p1234-e5678.adobeaemcloud.com \
        folder=/wknd-shared/en/adventures/napa-wine-tasting \
        propertyName=metadata/dc:rights \
        propertyValue="WKND Restricted Use" \
        file=service_token.json
    

    The output to the terminal looks like:

    code language-shell
    200 - OK @ https://author-p1234-e5678.adobeaemcloud.com/api/assets/wknd-shared/en/adventures/napa-wine-tasting.json
    403 - Forbidden @ https://author-p1234-e5678.adobeaemcloud.com/api/assets/wknd-shared/en/adventures/napa-wine-tasting/AdobeStock_277654931.jpg.json
    403 - Forbidden @ https://author-p1234-e5678.adobeaemcloud.com/api/assets/wknd-shared/en/adventures/napa-wine-tasting/AdobeStock_239751461.jpg.json
    403 - Forbidden @ https://author-p1234-e5678.adobeaemcloud.com/api/assets/wknd-shared/en/adventures/napa-wine-tasting/AdobeStock_280313729.jpg.json
    403 - Forbidden @ https://author-p1234-e5678.adobeaemcloud.com/api/assets/wknd-shared/en/adventures/napa-wine-tasting/AdobeStock_286664352.jpg.json
    

    The 403 - Forbidden lines, indicate errors in the HTTP API calls to AEM as a Cloud Service. These 403 Forbidden errors occur when attempting to update the assets’ metadata.

    The reason for this is the Service Credentials-derived access token authenticates the request to AEM using an auto-created technical account AEM user, that by default, only has read access. To provide the application write access to AEM, the technical account AEM user associated with the access token must be granted permission in AEM.

Configure access in AEM

The Service Credentials-derived access token uses a technical account AEM User that has membership in the Contributors AEM user group.

Service Credentials - Technical Account AEM User

Once the technical account AEM user exists in AEM (after first HTTP request with the access token), this AEM user’s permissions can be managed the same as other AEM users.

  1. First, locate the technical account’s AEM login name by opening the Service Credentials JSON downloaded from AEM Developer Console, and locate the integration.email value, which should look similar to: 12345678-abcd-9000-efgh-0987654321c@techacct.adobe.com.
  2. Log in to the corresponding AEM environment’s Author service as an AEM Administrator
  3. Navigate to Tools > Security > Users
  4. Locate the AEM user with the Login Name identified in Step 1, and open its Properties
  5. Navigate to the Groups tab, and add the DAM Users group (whom as write access to assets)
  6. Tap Save and Close

With the technical account permitted in AEM to have write permissions on assets, rerun the application:

$ node index.js \
    aem=https://author-p1234-e5678.adobeaemcloud.com \
    folder=/wknd-shared/en/adventures/napa-wine-tasting \
    propertyName=metadata/dc:rights \
    propertyValue="WKND Restricted Use" \
    file=service_token.json

The output to the terminal looks like:

200 - OK @ https://author-p1234-e5678.adobeaemcloud.com/api/assets/wknd-shared/en/adventures/napa-wine-tasting.json
200 - OK @ https://author-p1234-e5678.adobeaemcloud.com/api/assets/wknd-shared/en/adventures/napa-wine-tasting/AdobeStock_277654931.jpg.json
200 - OK @ https://author-p1234-e5678.adobeaemcloud.com/api/assets/wknd-shared/en/adventures/napa-wine-tasting/AdobeStock_286664352.jpg.json
200 - OK @ https://author-p1234-e5678.adobeaemcloud.com/api/assets/wknd-shared/en/adventures/napa-wine-tasting/AdobeStock_239751461.jpg.json
200 - OK @ https://author-p1234-e5678.adobeaemcloud.com/api/assets/wknd-shared/en/adventures/napa-wine-tasting/AdobeStock_280313729.jpg.json

Verify the changes

  1. Log into the AEM as a Cloud Service environment that has been updated (using the same host name provided in the aem command-line parameter)
  2. Navigate to the Assets > Files
  3. Navigate it the asset folder specified by the folder command-line parameter, for example WKND > English > Adventures > Napa Wine Tasting
  4. Open the Properties for any asset in the folder
  5. Navigate to the Advanced tab
  6. Review the value of the updated property, for example Copyright which is mapped to the updated metadata/dc:rights JCR property, which now reflects the value provided in the propertyValue parameter, for example WKND Restricted Use

WKND Restricted Use Metadata Update

Congratulations!

Now that we’ve programmatically accessed AEM as a Cloud Service using a local development access token, and a production-ready service-to-service access token!

recommendation-more-help
e25b6834-e87f-4ff3-ba56-4cd16cdfdec4