1

I had a scenarion where I need to give access to set of users access for a limited time of few hours/a day but only on certain days. So I use "TEMP CODE" approach, wherein I need to keep bothered to VERIFY in SF app each time they login. As they can use this to login anytime valid for 24 hours.

However, just I was searching through is there any way I can generate this TEMPORARY CODE programmatically, instead of logging in to SFMC each time just for the sake to generate this code. Any suggestion/alternate ways of granting access are welcome.

enter image description here

1 Answer 1

1
+50

My alternative idea for this is that you can let them have their own MC account user and their own MFA but you can control the access by activating/deactivating their account user through a cloud page link.

Note: Everything below needs to be in the MC Parent context.

Step 1, you need to have/create an installed package that is enabled for the Parent BU

The installed package scope should be something like this:

PROVISIONING section

  • Accounts: Read, Write
  • Users: Read, Write

Get the client credentials (client id and client secret)

Step 2, create a landing page in the Parent BU

The code for the cloud page is detailed below:

2.1 Get parameters

// GET PARAMETERS
var status = Platform.Request.GetQueryStringParameter("status");
var userName = Platform.Request.GetQueryStringParameter("username");

2.2 Get v2 access token

    // GET V2 ACCESS TOKEN 

    var debugging = false;

    // Client information
    var subDomain = 'YOUR SUBDOMAIN'
    var client_id = 'YOUR CLIENT ID';
    var client_sc = 'YOUR CLIENT SECRET';
    var payload = {
        "grant_type": "client_credentials",
        "client_id": client_id,
        "client_secret": client_sc
    };
    var url = 'https://' + subDomain + '.auth.marketingcloudapis.com/v2/token';
    var req = new Script.Util.HttpRequest(url);
    req.emptyContentHandling = 0;
    req.retries = 2;
    req.continueOnError = true;
    req.contentType = "application/json"; 
    req.method = "POST";
    // auth = 'Bearer ' + accesstoken;
    // req.setHeader("Authorization", auth); 
    req.postData = Stringify(payload); 
    var resp = req.send();
    var resultJSON = Platform.Function.ParseJSON(String(resp.content));
    if (debugging) {
        Write('access token: ' + resultJSON.access_token + '<br>');
        Write('expire in: ' + resultJSON.expires_in + '<br>');
    };
    var accesstoken = resultJSON.access_token;

2.3 get account user ID

// GET ACCOUNT USER ID
var accountUser = AccountUser.Retrieve({Property:"UserID",SimpleOperator:"equals",Value: userName});
var AccountUserID = accountUser[0].AccountUserID;

2.4 SOAP API call to update ActiveFlag attribute in AccountUser object

    // CALL API TO UPDATE ActiveFlag attribute
    var MID = "YOUR PARENT BU MID"; // YOUR PARENT BU MID

    var URL = 'https://' + subDomain + '.soap.marketingcloudapis.com/Service.asmx';
    var ContentType = 'text/xml';

    var Payload = '';
    Payload +=  '<?xml version="1.0" encoding="UTF-8"?>';
    Payload +=  '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">';
    Payload +=      '<s:Header>';
    Payload +=          '<a:Action s:mustUnderstand="1">Create</a:Action>';
    Payload +=          '<a:To s:mustUnderstand="1">https://' + subDomain + '.soap.marketingcloudapis.com/Service.asmx</a:To>';
    Payload +=          '<fueloauth xmlns="http://exacttarget.com">' + accesstoken + '</fueloauth>';
    Payload +=      '</s:Header>';
    Payload +=      '<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">';
    Payload +=          '<CreateRequest xmlns="http://exacttarget.com/wsdl/partnerAPI">';
    Payload +=              '<Options>';
    Payload +=                  '<SaveOptions>';
    Payload +=                      '<SaveOption>';
    Payload +=                          '<PropertyName>*</PropertyName>';
    Payload +=                          '<SaveAction>UpdateOnly</SaveAction>';
    Payload +=                      '</SaveOption>';
    Payload +=                  '</SaveOptions>';
    Payload +=              '</Options> ';
    Payload +=              '<Objects xsi:type="AccountUser">';
    Payload +=                  '<PartnerKey xsi:nil="true"></PartnerKey>';
    Payload +=                  '<ObjectID xsi:nil="true"></ObjectID>';
    Payload +=                  '<Client>';
    Payload +=                      '<ID>' + MID + '</ID>'; // Parent BU MID
    Payload +=                  '</Client>';
    Payload +=                  '<AccountUserID>' + AccountUserID + '</AccountUserID>'; // AccountUserID
    Payload +=                  '<ActiveFlag>'+ status +'</ActiveFlag>';
    Payload +=              '</Objects>';
    Payload +=          '</CreateRequest>';
    Payload +=      '</s:Body>';
    Payload +=  '</s:Envelope>';

    
    var result = HTTP.Post(URL, ContentType, Payload);

You may wonder why we don't convert it by the WSProxy library to have a simple version then can ignore the authenticate step but trust me you cannot (I tried)

You can read about the issue in this reference and this reference also. Thank you @Eliot and @Niko!

FYI it's not a bug but SFMC did it in purpose. I was told that this is a security measure to protect the user object.

Step 3 Activate and Deactivate a user

Just need edit the username, status and go the URL on your browser.

Activate a user:

https://cloud.CloudpageURLexample.com/YOUR_SITE_KEY?username=USERNAME&status=true

Deactivate a user:

https:///cloud.CloudpageURLexample.com/YOUR_SITE_KEY?username=USERNAME&status=false

Full code

<script runat="server">
Platform.Load("core", "1.1.1");

// GET PARAMETERS
var status = Platform.Request.GetQueryStringParameter("status");
var userName = Platform.Request.GetQueryStringParameter("username");

if (status && userName){

    // GET V2 ACCESS TOKEN 

    var debugging = false;

    // Client information
    var subDomain = 'YOUR SUBDOMAIN'
    var client_id = 'YOUR CLIENT ID';
    var client_sc = 'YOUR CLIENT SECRET';
    var payload = {
        "grant_type": "client_credentials",
        "client_id": client_id,
        "client_secret": client_sc
    };
    var url = 'https://' + subDomain + '.auth.marketingcloudapis.com/v2/token';
    var req = new Script.Util.HttpRequest(url);
    req.emptyContentHandling = 0;
    req.retries = 2;
    req.continueOnError = true;
    req.contentType = "application/json"; 
    req.method = "POST";
    // auth = 'Bearer ' + accesstoken;
    // req.setHeader("Authorization", auth); 
    req.postData = Stringify(payload); 
    var resp = req.send();
    var resultJSON = Platform.Function.ParseJSON(String(resp.content));
    if (debugging) {
        Write('access token: ' + resultJSON.access_token + '<br>');
        Write('expire in: ' + resultJSON.expires_in + '<br>');
    };
    var accesstoken = resultJSON.access_token;

    // GET ACCOUNT USER ID
    var accountUser = AccountUser.Retrieve({Property:"UserID",SimpleOperator:"equals",Value: userName});
    var AccountUserID = accountUser[0].AccountUserID;
    
    // CALL API TO UPDATE ActiveFlag attribute
    var MID = "PARENT BU MID"; // YOUR PARENT BU MID

    var URL = 'https://' + subDomain + '.soap.marketingcloudapis.com/Service.asmx';
    var ContentType = 'text/xml';

    var Payload = '';
    Payload +=  '<?xml version="1.0" encoding="UTF-8"?>';
    Payload +=  '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">';
    Payload +=      '<s:Header>';
    Payload +=          '<a:Action s:mustUnderstand="1">Create</a:Action>';
    Payload +=          '<a:To s:mustUnderstand="1">https://' + subDomain + '.soap.marketingcloudapis.com/Service.asmx</a:To>';
    Payload +=          '<fueloauth xmlns="http://exacttarget.com">' + accesstoken + '</fueloauth>';
    Payload +=      '</s:Header>';
    Payload +=      '<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">';
    Payload +=          '<CreateRequest xmlns="http://exacttarget.com/wsdl/partnerAPI">';
    Payload +=              '<Options>';
    Payload +=                  '<SaveOptions>';
    Payload +=                      '<SaveOption>';
    Payload +=                          '<PropertyName>*</PropertyName>';
    Payload +=                          '<SaveAction>UpdateOnly</SaveAction>';
    Payload +=                      '</SaveOption>';
    Payload +=                  '</SaveOptions>';
    Payload +=              '</Options> ';
    Payload +=              '<Objects xsi:type="AccountUser">';
    Payload +=                  '<PartnerKey xsi:nil="true"></PartnerKey>';
    Payload +=                  '<ObjectID xsi:nil="true"></ObjectID>';
    Payload +=                  '<Client>';
    Payload +=                      '<ID>' + MID + '</ID>'; // Parent BU MID
    Payload +=                  '</Client>';
    Payload +=                  '<AccountUserID>' + AccountUserID + '</AccountUserID>'; // AccountUserID
    Payload +=                  '<ActiveFlag>'+ status +'</ActiveFlag>';
    Payload +=              '</Objects>';
    Payload +=          '</CreateRequest>';
    Payload +=      '</s:Body>';
    Payload +=  '</s:Envelope>';

    
    var result = HTTP.Post(URL, ContentType, Payload);

    Write("Status code: " + result.StatusCode + "<br>");
    Write(Stringify(result.Response));
}
    
</script>

I hope you find it helpful!

2
  • 1
    Thank you @DucLe this is truly amazing! The provided solution is even more useful than I requested! Kudos to your efforts on this. Commented Jan 24 at 4:29
  • Thank you for your kind words @VishalKumarCV ;)
    – Duc Le
    Commented Jan 24 at 9:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .