Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

5. Adding Zitadel Actions

tbd - work in progress

6. Configuring SSO

tbd - work in progress

OLD DOCS (will get removed soon - wip)

Scope

This tutorial only applies for clients with a Customer Managed Tenant.

...

Note

If you add any action the function must string match the name of the action else it is not called.

Add one new action called addGrant with this contentZITADEL Actions are custom scripts that you can define to run at specific points during the authentication and authorization processes. After an action was added, it needs to be used by assigning it to one of the available Trigger Types.

Currently the following Actions need to be configured (as required).

Action: addGrant

  1. Create a new addGrant action

    image-20241119-140109.pngImage Added

    Note: add the appropriate roles based on needs

Code Block
function addGrant(ctx, api) {
    api.userGrants.push({
        projectID: '<Resource ID of granted project Unique Apps>',
        projectGrantID: '<Grant ID of granted project Unique Apps>',
        roles: ['chat.chat.basic'] // default roles users get
    });
}

The addGrant actions needs to react on the Trigger Type “Post Creation” because we want to add the default roles for the user after creation.

...

Action: addUserGroupsMetadataEntra

  1. If Entra is used as an IDP, create the action addUserGroupsMetadataEntra

...

Code Block
languagejs
const logger = require("zitadel/log")
const http = require('zitadel/http')
'chat.chat.unlimited', 'chat.chat.upload', 'chat.knowledge.read', 'chat.knowledge.write']
    });
}

This action has to be added as a Post Creation trigger in External Authentication flow.

Add another action called setEmailVerified with this content

Code Block
function setEmailVerified(ctx, api) {
    api.setEmailVerified(true)
}

This action has to be added as a Pre Creation trigger in External Authentication flow.

...


function addUserGroupsMetadataEntra(ctx, api) {
  logger.log('Writing group info on user metadata.');

  const claims = ctx.claimsJSON();
  const parsedGroups = JSON.parse(claims).groups;

  // Enable for debugging
  // logger.log('Claims: ' + JSON.stringify(claims));
  // logger.log('Parsed groups: ' + JSON.stringify(parsedGroups));

  // Get names with additional call to Graph API
  const batchRequests = [];
  for (const groupId of parsedGroups) {
    batchRequests.push({
      "id": groupId,
      "method": "GET",
      "url": `/groups/${groupId}`
    });
  }

  const graphApiBatchResponse = http.fetch('https://graph.microsoft.com/v1.0/$batch', {
    method: 'POST',
    headers: {
      "Authorization": `Bearer ${ctx.accessToken}`,
      "Content-Type": "application/json"
    },
    body: {
      requests: batchRequests
    }
  }).json();

  const entraGroups = [];
  for (const apiResponse of graphApiBatchResponse.responses) {
    const groupId = apiResponse.id;
    const groupName = apiResponse.body.displayName;

    entraGroups.push({
      "id": groupId,
      "displayName": groupName,
    });
  }

  // Check if groups are valid and do not contain empty string values
  if (entraGroups.some(group => group.id === "" || group.displayName === "")) {
    logger.log('Invalid groups found, skipping metadata update.');
    return;
  }

  // append metadata to user
  api.v1.user.appendMetadata("groups", entraGroups);
}

After you’ve added the action, you need to assign it to a trigger.

...

Action: addUserGroupsMetadataOidc

Code:

Code Block
const logger = require("zitadel/log")

function addUserGroupsMetadataOidc(ctx, api) {
  logger.log('Writing group info on user metadata.');

  const claims = ctx.claimsJSON();
  const parsedGroups = JSON.parse(claims).groups;

  // Enable for debugging
  // logger.log('Claims: ' + JSON.stringify(claims));
  // logger.log('Parsed groups: ' + JSON.stringify(parsedGroups));

  // To sync we need need the external groups' ID and display name
  // Verify how the groups are sent on the ID token and adapt to the desired format.
  let groups = parsedGroups.map(group => {
    return {
      "id": group.id,
      "displayName": group.displayName,
    };
  });

  // Check if groups are valid and do not contain empty string values
  if (groups.some(group => group.id === "" || group.displayName === "")) {
    logger.log('Invalid groups found, skipping metadata update.');
    return;
  }

  // append metadata to user
  api.v1.user.appendMetadata("groups", groups);
}

Flow Type: External Authentication
Trigger Type: Post Authentication
Actions: addUserGroupsMetadataOidc

...

Action: addUserGroupsMetadataSaml

Code:

Code Block
const logger = require("zitadel/log")

function addUserGroupsMetadataSaml(ctx, api) {
  logger.log('Writing group info on user metadata.');

  const sentGroups = ctx.v1.providerInfo?.attributes["groups"];

  // Enable for debugging
  // logger.log('Parsed groups: ' + JSON.stringify(sentGroups));

  // To sync we need need the external groups' ID and display name
  // Verify how the groups are sent on the ID token and adapt to the desired format.
  let groups = sentGroups.map(group => {
    return {
      "id": group.id,
      "displayName": group.displayName,
    };
  });

  // Check if groups are valid and do not contain empty string values
  if (groups.some(group => group.id === "" || group.displayName === "")) {
    logger.log('Invalid groups found, skipping metadata update.');
    return;
  }

  // append metadata to user
  api.v1.user.appendMetadata("groups", groups);
}

Flow Type: External Authentication
Trigger Type: Post Authentication
Action: addUserGroupsMetadataSaml

This action needs an additional action:

Action: prefilRegisterFromSAML

Code:

Code Block
function prefilRegisterFromSAML(ctx, api) {
	if (ctx.v1.externalUser?.externalIdpId != "xxxxxxx") {
        return
    }
    let firstname = ctx.v1.providerInfo?.attributes["GivenName"];
    let lastname = ctx.v1.providerInfo?.attributes["Surname"];
    let email = ctx.v1.providerInfo?.attributes["emailaddress"];
    
    
    if (firstname) {
    	api.setFirstName(firstname[0]);
    }
    if (lastname) {
	    api.setLastName(lastname[0]);
    }
    if (email) {
    	api.setEmail(email[0]);
	    api.setEmailVerified(true);
	    api.setPreferredUsername(email[0]);
    }
} 

Flow Type: External Authentication
Trigger Type: Post Authentication
Actions: prefilRegisterFromSAML

Don’t forget to add the IDP ID in the code above. You will find it in the IDP settings when clicking on the IDP and getting the ID from the URL

...

6. Configuring SSO

tbd - work in progress

...