Securing Marketing Cloud Apps hosted on CloudPages

In one of my previous posts, Simple Marketing Cloud App hosted on a CloudPage, I have outlined a solution for creating apps for use in Marketing Cloud and hosting them on CloudPages.

While you can choose to hide a CloudPage from being indexed by Google, it can still be accessed by anyone who has the link. That’s why to make your Marketing Cloud apps more secure, I will show you how to restrict access to those apps and CloudPages, so that they can only be accessed and used by your Marketing Cloud users who are logged in. The credit for this solution goes to Pato Spir from Devs United whom I would like to thank for sharing it!

Before we start, I assume that you already have an existing CloudPage with an app that you want to secure. If not, you can still test this solution by creating a very simple CloudPage with a text block saying “Hello world”. After implementing the solution described in this article, the text will only be visible to logged-in users, and users who are not logged in will be taken to the Salesforce Marketing Cloud login screen.

Once you have the CloudPage ready, copy the URL of that CloudPage, as you will need it in the next step.

Web App Integrations with Authorization Code Grant Type

In order to build a mechanism that will prevent external users from accessing the CloudPage/App, we will create a new integration in Marketing Cloud and use the authorization code flow to authorize your users.

Let’s start by creating and configuring a new integration package in Marketing Cloud:

  1. In Marketing Cloud, go to Setup > Apps > Installed Packages.
  2. Click New.
  3. Give the package a name and description.
  4. Save the package.
  5. Under Components, click Add Component, and select an API Integration component.
  6. Under Integration Type, choose Web App and click next.
  7. Under Redirect URIs, paste the link to the CloudPage that hosts your app.
  8. The scope is not required, so leave all checkboxes blank. Save the package.

Make a note of the Client Id and Secret and your 28 characters tenant-specific subdomain, as you will need those later.

Note: If your users’ default business unit is different than the BU where you install the package, make sure to assign access to the package to your users in both BUs, in their default BU and in the BU which hosts your app. You can do that by going to the Access tab from the detailed view for your package. For more details, see Manage Licensing for Installed Packages.

Authorization Code Flow

In the authorization code flow, end users are redirected to Marketing Cloud to authorize your application to act on their behalf. After the redirect, the user gives authorization to your application by logging in to Marketing Cloud. After login, Marketing Cloud redirects the user to your application’s redirect URL, which you specify when you create the API integration in Installed Packages. As part of this redirect, Marketing Cloud appends an authorization code to the redirect URL for your application to use. Your application then uses the authorization code to request an access token from Marketing Cloud.

Source: https://developer.salesforce.com/docs/atlas.en-us.noversion.mc-app-development.meta/mc-app-development/integration-app-auth-code.htm

Authorization Script

The script will check if the user is logged in, and if not, the user will be asked to log in to Marketing Cloud using their credentials. Once the user logs in, a cookie will be set with the value of the access token. In the below script, you will need to add:

  • Client Id from the Installed Package you created earlier,
  • Client Secret from the Installed Package you created earlier,
  • The 28 character subdomain used in your tenant-specific endpoints (eg. mcx3g7dtegr6hh7y5h7grhrgr97n),
  • The URL of the CloudPage that hosts your app.

You can add the below script to the CloudPage’s HTML in the Code View or simply create a new HTML block at the beginning of your CloudPage and paste it there:

<script runat="server">
Platform.Load("core", "1");
var client_id = "xxxxx", //add the client id from the installed package
client_secret = "xxxxxx", //add the client secret from the installed package
subdomain = "xxxxx", //add the 28 character subdomain (starts with mc….)
redirect_uri = "xxxxx"; //add the url of the CloudPage that hosts your app
var auth = true;
var authToken = Platform.Request.GetCookieValue("authToken");
if (authToken == null) {
var authCode = Request.GetQueryStringParameter("code");
if (authCode == null) {
Platform.Response.Redirect('https://&#39; + subdomain + '.auth.marketingcloudapis.com/v2/authorize?response_type=code&client_id=' + client_id + '&redirect_uri=' + redirect_uri);
} else {
var url = 'https://&#39; + subdomain + '.auth.marketingcloudapis.com/v2/token'
var contentType = "application/json";
var payload = {
"grant_type": "authorization_code",
"code": authCode,
"client_id": client_id,
"client_secret": client_secret,
"redirect_uri": redirect_uri
};
try {
var accessTokenRequest = HTTP.Post(url, contentType, Stringify(payload));
if (accessTokenRequest.StatusCode == 200) {
var tokenResponse = Platform.Function.ParseJSON(accessTokenRequest.Response[0]);
var accessToken = tokenResponse.accessToken;
Platform.Response.SetCookie("authToken", accessToken);
auth = true;
}
} catch (error) {
auth = false;
}
}
}
</script>

For more advanced use cases, you could enhance this solution by adding a state query string when requesting a code to see if it matches a value that you previously set. See more details here and an outline of the solution here.


Questions? Comments?

Leave a comment below or email me at zuzanna@sfmarketing.cloud.

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 )

Connecting to %s