Securing Custom Marketing Cloud Apps with JSON Web Tokens (JWT)
Introduction
In today's digital landscape, custom apps play a vital role in enhancing the functionality and user experience of marketing cloud platforms. However, with the increasing need for security, it's crucial to implement robust authentication and authorization mechanisms to protect sensitive data and ensure secure interactions between the app and the marketing cloud. JSON Web Tokens (JWT) have emerged as a popular and efficient solution for securing custom apps in marketing cloud environments. This blog will explore the fundamentals of JWT, its benefits, and how to use it effectively to secure custom apps in marketing cloud.
1. Understanding JSON Web Tokens (JWT)
JSON Web Token (JWT) is a compact, URL-safe, and self-contained token format designed to securely transmit information between parties. It is digitally signed and can be verified by the parties involved, ensuring the integrity of the data it carries. JWTs consist of three parts:
- Header: Contains information about the type of token and the signing algorithm used.
{ "alg": "HS256", "typ": "JWT" }
- Payload: Contains the claims, which are statements about the user or additional data. Claims can include
user information, permissions, and other relevant data.
{ "sub": "1234567890", "name": "John Doe", "admin": true }
- Signature: Created using the header, payload, and a secret key, the signature ensures the token's integrity
and authenticity.
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
2. The Benefits of JWT in Marketing Cloud Apps
Implementing JWT in custom marketing cloud apps offers numerous advantages:
- Stateless: JWTs are stateless, meaning the server does not need to store user session information. This allows for easy scalability and reduces server-side load.
- Cross-platform compatibility: JWT is supported across various programming languages and platforms, making it an ideal choice for heterogeneous marketing cloud environments.
- Security: JWTs are digitally signed, ensuring data integrity and protecting against tampering or unauthorized modifications.
- Reduced server load: By eliminating the need for session storage, JWTs reduce the burden on the server, leading to improved performance.
- Seamless integration: JWTs can be easily integrated into existing marketing cloud app architectures, minimizing the need for significant changes to the current setup.
3. Generating and Verifying JWTs in Marketing Cloud Apps
Let's explore the steps to generate and verify JWTs for securing custom apps in marketing cloud environments:
- Step 1: User Authentication
When a user logs into the custom app, the authentication process takes place. The marketing cloud app's authentication system should validate the user's credentials and generate a JWT as a response. - Step 2: JWT Generation
The JWT is created by combining the user's claims, a unique secret key known only to the marketing cloud app and the marketing cloud server, and a specified signing algorithm (such as HMAC SHA-256). The resulting JWT is then returned to the user. - Step 3: Token Storage
Once the user receives the JWT, it can be stored in the app's local storage or as an HTTP-only cookie, depending on the level of security required. - Step 4: API Requests
For each subsequent API request to the marketing cloud server, the custom app should include the JWT in the request header, usually in the "Authorization" field as a Bearer token. - Step 5: Token Verification
On the server-side, the marketing cloud platform will receive the JWT in the API request. It will then validate the token's signature using the secret key it shares with the custom app. If the signature is valid, the marketing cloud server can trust the claims within the token and process the API request accordingly.
Conclusion
JSON Web Tokens (JWT) provide an efficient and secure method for safeguarding custom apps in marketing cloud environments. By implementing JWT-based authentication and authorization mechanisms, marketing cloud platforms can enhance the overall security of their custom apps, protect sensitive data, and create a seamless user experience. As marketing technologies continue to evolve, leveraging JWTs for securing custom apps becomes an essential aspect of a successful and trustworthy marketing cloud ecosystem.
Reference:
For more in-depth information about JSON Web Tokens (JWT), you can refer to the official website of JWT.IO. The website provides a comprehensive introduction to JWT, its specifications, use cases, and practical examples.
Website : JWT.IO - Introduction to JSON Web Tokens
By visiting this resource, you can gain a deeper understanding of JWT and its applications, which will help you implement secure authentication and authorization mechanisms for your custom apps in the marketing cloud environment.
Full Code
<script runat="server">
// Load the Platform Core library with version 1
Platform.Load("core", "1");
// Define the name of the Data Extension used to log API exceptions
var errorLogDEInit = "CustomAppException";
// Main Block: This is the main logic of the script that processes incoming requests and generates responses.
try {
// Retrieve the POST data from the request
var jsonPost = Platform.Request.GetPostData();
var json = Platform.Function.ParseJSON(jsonPost);
// Initialize the HTTPProperties Data Extension and add a row with request information
var HTTPPropertiesDE = DataExtension.Init("HTTPProperties");
HTTPPropertiesDE.Rows.Add({
Browser: Platform.Request.Browser,
ClientIP: Platform.Request.ClientIP,
HasSSL: Platform.Request.HasSSL,
IsSSL: Platform.Request.IsSSL,
Method: Platform.Request.Method,
QueryString: Platform.Request.QueryString,
ReferrerURL: Platform.Request.ReferrerURL,
RequestURL: Platform.Request.RequestURL,
UserAgent: Platform.Request.UserAgent
});
if (Platform.Request.Method == "GET") {
// If the HTTP method is GET, return a "403 Forbidden" message
var response = {
"message": "403 Forbidden"
};
} else {
switch (json.operation) {
case "RequestToken":
// Call the GetAccessToken function to retrieve the access token
var secret = GetAccessToken(json, errorLogDEInit);
// Generate the JWT using the GetJWT function
var jwt = GetJWT(jsonPost, secret, errorLogDEInit);
// Create the response object with the JWT and token type
var response = {
"access_token": jwt,
"token_type": "Bearer"
};
break;
default:
// Create an error response object for invalid operations
var response = {
"Error": "Invalid operation specified."
};
}
}
// Output the response as a string
Write(Stringify(response));
} catch(ex) {
// Exception handling: Log the error details into the errorLogDEInit Data Extension
var APIExceptionDE = DataExtension.Init(errorLogDEInit);
APIExceptionDE.Rows.Add({
Message: ex.message,
Description: ex.description,
InnerException: ex.jintException,
FunctionName: "Main Block"
});
// Return an error response as a string in case of an exception
var response = {
"Error": ex.message
};
Write(Stringify(response));
}
/**
* This function retrieves the access token based on the provided credentials.
* @param {Object} credentials - An object containing the authentication credentials.
* @param {string} credentials.grant_type - The grant type for authentication.
* @param {string} credentials.client_id - The client ID for authentication.
* @param {string} credentials.client_secret - The client secret for authentication.
* @param {DataExtension} errorLogDEInit - The Data Extension used to log API exceptions.
* @returns {Object} - An object containing the access token and related information.
* @throws {Error} - If an exception occurs during execution, it is logged in the errorLogDEInit Data Extension and re-thrown.
*/
function GetAccessToken(credentials, errorLogDEInit) {
try {
// Function logic for GetAccessToken...
// This function should handle retrieving the access token based on the provided credentials.
// It may interact with a database or external service to validate the credentials and return the access token.
// In case of missing or invalid credentials, appropriate error responses should be generated.
if (!credentials.grant_type || !credentials.client_id || !credentials.client_secret) {
return {
"errorcode": 0,
"message": "missing credentials, make sure you have add grant_type, client id and secret."
};
}
else{
var appCredentialsDE = DataExtension.Init("AppCredentials");
var complexfilter = {
LeftOperand:{
Property:"client_id",
SimpleOperator:"equals",
Value:credentials.client_id
}
,
LogicalOperator:"AND",
RightOperand:{
Property:"client_secret",
SimpleOperator:"equals",
Value:credentials.client_secret
}
};
var dataSet= appCredentialsDE.Rows.Retrieve(complexfilter);
if (!dataSet || dataSet.length === 0)
{
var response={
"message": "Not Authorized. Please validate your credentials.","code":400};
return response;
}
else{
return (dataSet[0].signing_secret);
}
}
} catch (ex) {
// Exception handling: Log the error details into the errorLogDEInit Data Extension
var APIExceptionDE = DataExtension.Init(errorLogDEInit);
APIExceptionDE.Rows.Add({
Message: ex.message,
Description: ex.description,
InnerException: ex.jintException,
FunctionName: "GetAccessToken"
});
throw ex;
}
}
/**
* Generates a JSON Web Token (JWT) from the provided JSON payload using a predefined key and algorithm.
*
* @param {string} payload - The JSON payload to be used for generating the JWT.
* @param {string} signingSecret - The signingSecret to be used for generating the JWT.
* @param {string} errorLogDEInit - The name of the Data Extension where exceptions will be logged.
* @returns {string} The generated JWT as a string.
* @throws {Error} If an exception occurs during JWT generation, it will be caught, logged, and rethrown.
*/
function GetJWT(payload, signingSecret, errorLogDEInit) {
try {
// Function logic for GetJWT...
// This function should handle generating a JSON Web Token (JWT) from the provided payload using the given signing secret and algorithm.
// The generated JWT should be returned as a string.
// In case of any exceptions during JWT generation, appropriate error responses should be generated and logged.
// Set the value of the "@JSON" variable to the provided JSON payload
Variable.SetValue("@JSON", payload);
Variable.SetValue("@Secret", signingSecret);
// Define the AMPscript block to generate the JWT using the GetJWT function
var ampScriptBlock = "\%\%[SET @JWT = GetJWT(@Secret, 'HS256', @JSON)]\%\%";
// Process the AMPscript block and execute it
Platform.Function.TreatAsContent(ampScriptBlock);
// Return the generated JWT value
return Variable.GetValue('@JWT');
} catch (ex) {
// Exception handling: Log the error details into the errorLogDEInit Data Extension
var APIExceptionDE = DataExtension.Init(errorLogDEInit);
APIExceptionDE.Rows.Add({
Message: ex.message,
Description: ex.description,
InnerException: ex.jintException,
FunctionName: "GetJWT"
});
throw ex;
}
}
</script>
Comments
Post a Comment