Setting a SAML Attribute in an Action Fails
Last Updated:
Overview
When making api.samlResponse.setAttribute call within a callback function, the set attribute is missing in the SAML response. This article explains why and how to pass the attribute correctly.
Here is a simple example that reproduces the issue:
exports.onExecutePostLogin = async (event, api) => {
api.samlResponse.setAttribute("test1", "value1");
setTimeout(function(){
console.log("===== async delayed message =====");
api.samlResponse.setAttribute("test2", "value2");
}, 1000);
};
Here is the SAML response, stripping the unrelated sections, "test2" claim is missing in the SAML response.
<samlp:Response ...>
....
<saml:Assertion ....">
....
</saml:AuthnStatement>
<saml:AttributeStatement ...>
<saml:Attribute Name="test1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue xsi:type="xs:string">
value1
</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>Applies To
- SAML Attribute
- Action
Solution
Here is a modified sample, which will help to have both attributes in the SAML response.
const util = require('util');
exports.onExecutePostLogin = async (event, api) => {
const sleep = util.promisify(setTimeout)
async function addNewAttributeSync() {
console.log("===== synced delayed message =====");
await sleep(1000);
api.samlResponse.setAttribute("test2", "value2");
}
api.samlResponse.setAttribute("test1", "value1");
await addNewAttributeSync();
};
This issue can happen when an action makes an API call, and the callback handler executes api.samlResponse.setAttribute to set a claim. This function will then need to be converted to a Promise (E.g., using a utility function like util.promisify) such that the external API call is synchronized.