Expand my Community achievements bar.

SOLVED

Managing the Access token for a Server to Server Configuration

Avatar

Level 7

Hello Team,

 

Recently I am working on a POC task, where I need to get details from Adobe Analytics and show the details in my AEM applications home page.  So, basically this is a serer to sever connection, where I am displaying application specific data in my application.  Consider: I am trying to get the most visited pages, and displaying in descending order based on visitor count. 

Based on few articles, I was able to crack the logic to display the Adobe analytics data.

https://developer.adobe.com/developer-console/docs/guides/authentication/ServerToServerAuthenticatio... 

https://adobedocs.github.io/analytics-2.0-apis/ 

https://developer.adobe.com/analytics-apis/docs/2.0/guides/endpoints/reports/ 

 

From this, I am able to get the access token too.

https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/generate-server-to-server-...  Special thanks to @Imran__Khan  for his quick help.

 

From above I was able to get the response: Response {"access_token":"eyJhbSomeLetters","token_type":"bearer","expires_in":86399}  Whether I will get refresh token here??? Not sure. Let me explore.

 

Now, my major query is: Ideally I should not save this access token in user browser cookie. Since, I need to use a single access token for all the end user request, until the token expires. How can I implement this logic? 

I hope for every application to application integration (i mean AEM to Adobe Analytics or any other AEM app integration), concept of using the access token (which is specific to application)remains the same. So, I am curious to know from others, how you are managing to keep the access token in server?  Note: My AEM application has 3 publisher environment.

Also, one more observation: What is this article? Related to Integration with Adobe Analytics using IMS

https://experienceleague.adobe.com/docs/experience-manager-65/content/sites/administering/integratio... 

 

cc @Imran__Khan  @kautuk_sahni @aanchal-sikka @Jörg_Hoh @BrianKasingli @Raja_Reddy  @EstebanBustamante @arunpatidar @lukasz-m 

1 Accepted Solution

Avatar

Correct answer by
Level 10

@Mahesh_Gunaje Please user Sling Content Distribution(to publish content to different ) or Sticky session to have a publish and dispatcher one to one mapping and maintain publish specific access token.

View solution in original post

11 Replies

Avatar

Level 10

@Mahesh_Gunaje You will be getting access and refresh token. Access token to make subsequent calls until it is expired. Get new access token with the help of refresh token.

Save this access token somewhere in AEM crx/de and create service user having very specific access to fetch access and refresh token from crx/de node. Replace tokens every time you get new one. 

Avatar

Community Advisor

@Mahesh_Gunaje 

 

Since its a server-to-server communication, so there is no need to save this token in Browser.

Prefer to save it in CRX /var nodes, but encrypted.

Please find the encryption APIs here: https://www.tothenew.com/blog/aem-encryption-service-what-how-why/

 

Also, use the refresh token mechanism as suggested by @Imran__Khan 


Aanchal Sikka

Avatar

Level 7

Thanks @aanchal-sikka   @Imran__Khan   for your help. I have checked the article: https://www.tothenew.com/blog/aem-encryption-service-what-how-why/

This looks good. But query is, using this, I can save the client id, client secret in an encrypted way in configuration file. That is fine. But in the case of Access token, This will be generated at the run time. Suppose, Just imagine, once this feature is moved to the production, for the 1st user request,(this request went to prod Pub1 instance) generated access token. Then, using service user I have saved this details in crx /var node.  Then, I need to pass/use the same access token in other prod publish environment? So, need to use reverse replication?

Or else, I need to use sling scheduler concept?  Since token expiration time is 24 hours. So, call Sling scheduler for every day ( or 2 times per day, just for the safer side) from prod author. get access toke, refresh token. Save it in crx /var in an encrypted way. Replicate to prod publisher environments?? 

I am happy to clarify all your doubts

 

cc @Imran__Khan  @kautuk_sahni  @Jörg_Hoh @BrianKasingli @RajaReddy_3370  @EstebanBustamante @arunpatidar @lukasz-m 

Avatar

Level 10

In this case author will not be there in picture. It all about publishers and sync data between publish instances. I would suggest to implement sticky session which will make sure to call s
https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/aem-dispatcher-sticky-sess...

Avatar

Level 7

Hi @Imran__Khan 

True. Author will not come into the picture. We have 3 publisher, 3 dispatcher environment. Each dispatcher is mapped to particular publisher environment. Load balancing is taken care by AWS's  ALB (Application Load Balancer) feature. So, now, my major task is to sync data (Access token, refresh token) between multiple publisher environment.

Avatar

Level 10

@Mahesh_Gunaje Please user Sling Content Distribution(to publish content to different ) and Sticky session to have a publish and dispature one to one mapping.

Avatar

Community Advisor

Hello @Mahesh_Gunaje 

 

The same article also discusses about the multi publisher set-up.

Refer to section "

Steps to sync keys across all instances for AEM 6.3 or above:" on AEM Encryption Service: What, How & Why | TO THE NEW Blog


Aanchal Sikka

Avatar

Level 7

Hi @aanchal-sikka 

 

 I have checked the article. In that article, they are explaining about encrypting, decrypting the texts: client id, secret . also, to make sure these are proper in all the publisher environment. So, developer knows these values before the deployment(ie before run time). So that they can keep the encrypted keys in configuration files.  This scenario is valid in my case, provided Application specific access key is same/valid for, just consider 1 year (Just a hypothetical case). But in my case, access key is like: Dynamic value. I mean need to change access token for every 24 hours. So, I cannot use the steps that is mentioned in the given article.

So, the only steps I can think of is: as mentioned by @Imran__Khan  

"Save this access token somewhere in AEM crx/de and create service user having very specific access to fetch access and refresh token from crx/de node. Replace tokens every time you get new one."

So, in this case, I need to pass the same access token to remaining publish environments.  How can I achieve this? 

 

-Thanks

cc @Imran__Khan   @kautuk_sahni @arunpatidar 

 

 

 

Avatar

Correct answer by
Level 10

@Mahesh_Gunaje Please user Sling Content Distribution(to publish content to different ) or Sticky session to have a publish and dispatcher one to one mapping and maintain publish specific access token.

Avatar

Level 10

@Mahesh_Gunaje You will be getting an access token in response. Use access token to make subsequent calls until it is expired. Every time get new access token once it is expired.

As suggested by @aanchal-sikka, save encrypted access token under AEM crx/de /var/project/token node and create service user having very specific access to fetch access token from crx/de node. Replace tokens every time you get new one.

You can use below sample code to generate access token. 

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;;

import java.util.*;

public class TokenEncryptionDecryption {

    static byte[] encode;

    private static final String ALGORITHM = "AES";

    private static final String SUN_JCE = "SunJCE";

    private static final String ALGO = "AES/GCM/NoPadding";

    /* START AEM encryption */
    public static SecretKey generateSecretKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
        keyGenerator.init(256);
        return keyGenerator.generateKey();
    }

    /* Start encryption */
    public static String encrypt(String plaintext, SecretKey secretKey) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGO);

        byte[] iv = new byte[12];
        Cipher.getInstance(ALGO, SUN_JCE);
        GCMParameterSpec spec = new GCMParameterSpec(128, iv);

        cipher.init(Cipher.ENCRYPT_MODE, secretKey,spec);

        byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }
    /* END encryption */

    /* Start decryption */
    public static String decrypt(String encryptedText, byte[] encode) throws Exception {

        SecretKey secretKey = new SecretKeySpec(encode, 0, encode.length, ALGORITHM);
        Cipher cipher = Cipher.getInstance(ALGO, SUN_JCE);
        byte[] iv = new byte[12];
        GCMParameterSpec spec = new GCMParameterSpec(128, iv);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);

        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

        return new String(decryptedBytes);
    }
    /* End decryption */

    public static void main(String[] args) throws Exception {

        // Generate a secret key (or you can use a pre-shared key)
        SecretKey secretKey = generateSecretKey();
        encode = secretKey.getEncoded();

        // Save this also in CRX/DE
        String encoded = Base64.getEncoder().encodeToString(encode);

        String clientId = "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3";
        System.out.println("clientId: " + clientId);

        String encryptedClientId = encrypt(clientId, secretKey);
        System.out.println("Encrypted Client ID: "+encryptedClientId);

        // Get from crx/de and decode back in to Byte array.
        encode = Base64.getDecoder().decode(encoded);
        String decryptedText = decrypt(encryptedClientId, encode);
        System.out.println("Decrypted Text: " + decryptedText);

    }
}

 

Avatar

Level 1

@Mahesh_Gunaje  - you can keep/save multiple access token on all different Publisher P1, P2 (agreed token will be different and they are their own lifecycle and valid for 24hr). While request will come from LB, it could get connect on anyone of Publisher P1, P2, utilize the existing saved token for doing connection and fetch the results. Once access token will get expire then generate and save it again.