Platform Cache – Using it to store the access token if there is no refresh token mechanism provided

In my last post, I explained pretty much about the Platform cache and that was more theoretical. This post explains a use case where I used the Platform cache in my project. I had a challenge while working on a 3rd party application integration using OAuth 2 where I couldn’t refresh the access token as this mechanism has not been implemented by the 3rd party application vendor. In order to keep the process run, I needed the access token every time which requires the user interaction to authorize the users.

I am assuming that you are aware of the Salesforce Platform Cache and it’s used. If you are not familiar with Platform Cache then I would suggest you, read my last post.

Let me explain my use case in more details before we jump over to the solution. I wanted to send details about a campaign to a 3rd party application and it requires access token in the authorization header which we get in the OAuth 2 flow. For sending info to 3rd party application, I created a VF page (SyncToDemoApp)  which calls an Apex method from the page action in order to send information to 3rd party server.

SyncToDemo Visualforce page which is attached to a button on Campaign

 <apex:page standardController="Campaign" extensions="SyncToDemoAppController" action="{!initSync}">
 </apex:page>

To initiate the sync process, I needed a different page where I can authorize the user and get the access token. As you know, we have a redirect URL configured on the 3rd party application server where users redirected with the authorize code. Just think of google integration with SF. I will explain the code of SyncToDemoAppController class later.

Your application sends a token request to the Google Authorization Server, receives an authorization code, exchanges the code for a token, and uses the token to call a Google API endpoint.

Visualforce page for authorization

 <apex:page standardController="Campaign" extensions="ConnectToAppController" action="{!getAccessToken}">
 </apex:page>

Apex Controller for the above page

public class ConnectToAppController {
   Private static FINAL String MY_CLIENT_ID;
   Private static FINAL String MY_REDIRECT_UI;
   Private static FINAL String MY_CLIENT_SECRET ;
   private String campaignId;
   public ConnectToAppController(ApexPages.StandardController controller) {
      campaignId = controller.getId();
   }

   public PageReference getAccessToken() {
 
      // Check if page has loaded after redirecting from the **mydemoapp**
      // If its loaded from the redirection then it must have an authorization code
      // If authorization code found in the URL then we will make an api callout to get the access token
      // Otherwise will redirect user to authorize url of the application
      String authorization_code = ApexPages.currentPage().getParameters().get('code');
      If(authorization_code == null) {
         // Get the authorization code
         PageReference authorizeUrl = new PageReference('https://auth.mydemoapp.com/oauth/authorize?client_id=' + MY_CLIENT_ID + '&redirect_uri=' + MY_REDIRECT_UI + '&response_type=code');
         return authorizeUrl;
      } 
      else {

         Http http = new Http();
         HttpRequest request = new HttpRequest();
         // Get the access token
         request.setEndpoint('https://auth.mydemoapp.com/oauth/token?client_id=' + CLIENT_ID + '&client_secret=' + CLIENT_SECRET + '&code=' + authorization_code + '&grant_type=authorization_code');
         request.setHeader('Content-Type', 'application/x-www-form-urlencoded');
         request.setMethod('POST');
         HttpResponse response = http.send(request);
         if (response.getStatusCode() == 200) {
            Map < String, Object > results = (Map < String, Object > ) JSON.deserializeUntyped(response.getBody());
            System.debug(results);
            // We will have to save these values in the cache for later use 
            Cache.Session.put(campaignId + 'accessToken', (String) results.get('access_token'), 300); // You can set this time as per your token expired time
            Cache.Session.put(campaignId + 'refreshToken', (String) results.get('refresh_token'), 300);
            // Access token is not supported by this app that's the main reason we are using the
            // Platform cache here
         }
         else {
            // To debug the error, you can add the message to show on the page here
            System.assert(false, response.getBody());
         }
         // Now, we will have to redirect user to the referrer page 
         // We are saving the referrer url in Platform cache
         // To get the referrer URL, we will have to get the value using the key

         PageReference referrer_page = (PageReference) Cache.Session.get(campaignId + 'referrerUrl');
         return referrer_page;
      }
   }
}

Now, I think we have almost covered the authorization part. We just need to do some intelligent work in SyncToDemoAppController class. Here, we will check for the access token in Platform Cache. If we get the null for access_token key then we will redirect the user to the authorization page.

SyncToDemoAppController  Apex class

public class SyncToDemoAppController {
   String campaignId;
   public SyncToDemoApp(ApexPages.StandardController controller) {
      campaignId = controller.getId();
   }
 
   public PageReference initSync() {

      // Check if access_token is found in the platform cache
      if(Cache.Session.get(campaignId + 'accessToken') == null) {
         // Set the referrer for this campaign 
         Cache.Session.put(campaignId + 'referrerUrl', ApexPages.currentPage());
         // Redirect user to authorization page
         return new PageReference('/apex/ConnectToApp?id=' + campaignId);
      }
      // You can call the api methods by setting the authorization 
      // header of your http request
     else {
        String accessToken = (String) Cache.Session.get(campaignId + 'accessToken');
        // API Callouts
        // If you get token expired response then again send user to authorize page
        return new PageReference('/' + campaignId);
     }
   }
}

I found this solution very useful where we don’t have a refresh token mechanism to renew the access token. If your app allows you to renew the access token then I would not recommend this solution.  Please do let me know if you have any suggestion/feedbacks.

Keep visiting SFCURE!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s