Configure User providers
Configure user providers increases administration efficiency by removing the need to replicate and synchronize user groups created and maintained in your System of Record’s (SoR) identity providers configuration settings.
Microapps admins can configure user providers to collect user and user group data from your SoR and use this data to manage microapp subscriptions in all integrations. To configure user providers, your application SoR must provide APIs that expose users/user groups, for example ServiceNow, Salesforce, Jira, and so on.
Create user provider
You can either create a new user provider manually or import a user provider that is already configured.
Follow these steps:
-
From the Microapp Integrations page, select the User Providers tab in the top bar.
- Choose a user provider type. Select Create a new user provider from your HTTP web service to configure this user provider manually. You can also Import a previously configured user provider. For more information on importing, see Import.
- Enter a User provider name for the connection.
- Enter the user provider Base URL.
- Select an Icon for the user provider from the Icon Library, or leave this as the default icon.
- Select the Service authentication method, and complete all required details based on the authentication method that you use. For more information on authentication methods, see Set up Service Authentication.
- (Optional) Enable the Enable request rate limiting toggle if needed and enter a Number of requests and a Time interval.
- (Optional) Enter a value for Request timeout if needed.
-
Select Add to finish creating the user provider.
Now you import a script to finish.
Import script
Using the User provider script capability in Microapps, you need to upload a script to finish the user provider setup. We’ve provided script requirements and a JavaScript model below. See Prepare your script. For general information about scripting, see HTTP integration scripting.
After you added the user provider (in the previous procedure), the page opens with a view of your user providers. Follow these steps to add the script.
- Select Add script under Status.
- Select Import script.
-
Drag your script onto the import pop-up, or browse for the file. The script must be a .js file no larger than 1 MB.
The script is parsed and validated.
-
Select Import to finish.
You can see scripting details under Script handlers in the User provider script view of the user provider. To see requests made by the script, select the menu next to the user provider entry and select Sync log.
Your new user provider is now available when assigning subscribers. For more information, see Manage subscribers.
Prepare your script
When preparing your script, consider the following requirements:
- The import script must start by loading the built-in library microapp-user-groups. This library defines the objects that must be stored in the database:
const { User, Group, UserGroupMapping } = library.load("microapp-user-groups");
-
Objects have the following structure/properties:
-
User(accountName, displayName, email, domain, userPrincipalName, userId)
Email addresses must be unique within user provider -
Group(accountName, displayName, domain, userPrincipalName, groupId, parentGroupId)
Group hierarchy is also defined using parentGroupId -
UserGroupMapping(userId, groupId)
Maps users to groups
-
- All properties are of data type
STRING
. - User.email has to match the email of a user logged in to Citrix Workspace.
Model script
Use the following JavaScript code as a model.
Note
The following model is written specifically for the ServiceNow SoR. This script is not compatible with other services.
const { User, Group, UserGroupMapping } = library.load("microapp-user-groups");
function fullSync(params) {
fullSyncUsers(params);
fullSyncGroups(params);
fullSyncUserGroupMapping(params);
}
function fullSyncUsers({ client, dataStore }) {
let offset = 0;
do {
const response = client.fetchSync(
`/api/now/table/sys_user?sysparm_fields=sys_domain_path%2Cname%2C%20sys_id%2Cuser_name%2Cemail&sysparm_query=emailISNOTEMPTY^active%3Dtrue&sysparm_limit=100&sysparm_offset=${offset}`
);
if (!response.ok) {
console.log("Error status:", response.status, response.statusText);
console.log("Error body:", response.textSync());
throw new Error("Network response was not ok");
}
console.log("fetch done");
const users = response.jsonSync().result;
console.log("users");
users.map((user) =>
console.log(
user.user_name,
user.name,
user.email,
user.sys_domain_path,
user.name,
user.sys_id
)
);
dataStore.save(
User.tableModel,
users.map(
(user) =>
new User(
user.user_name,
user.name,
user.email,
user.sys_domain_path,
user.user_name,
user.sys_id
)
)
);
offset = offset + 100;
console.log(`offset: ${offset}`);
} while (offset < 300);
}
function fullSyncGroups({ client, dataStore }) {
let offset = 0;
do {
const response = client.fetchSync(
`/api/now/table/sys_user_group?sysparm_query=active%3Dtrue&sysparm_limit=100&sysparm_offset=${offset}`
);
if (!response.ok) {
console.log("Error status:", response.status, response.statusText);
console.log("Error body:", response.textSync());
throw new Error("Network response was not ok");
}
const groups = response.jsonSync().result;
groups.map((group) =>
console.log(
group.name,
group.name,
"/",
group.name,
group.sys_id,
group.parent.value
)
);
dataStore.save(
Group.tableModel,
groups.map(
(group) =>
new Group(
group.name,
group.name,
"/",
group.name,
group.sys_id,
group.parent.value
)
)
);
offset = offset + 100;
console.log(`offset: ${offset}`);
} while (offset < 400);
}
function fullSyncUserGroupMapping({ client, dataStore }) {
let offset = 0;
do {
const response = client.fetchSync(
`/api/now/table/sys_user_grmember?&sysparm_limit=100&sysparm_offset=${offset}`
);
if (!response.ok) {
console.log("Error status:", response.status, response.statusText);
console.log("Error body:", response.textSync());
throw new Error("Network response was not ok");
}
const mappings = response.jsonSync().result;
mappings.map((mapping) =>
console.log(mapping.user.value, mapping.group.value)
);
dataStore.save(
UserGroupMapping.tableModel,
mappings.map(
(mapping) =>
new UserGroupMapping(mapping.user.value, mapping.group.value)
)
);
offset = offset + 100;
console.log(`offset: ${offset}`);
} while (offset < 400);
}
integration.define({
synchronizations: [
{
name: "snowUserGroups", // Logical name
fullSyncFunction: fullSync,
},
],
model: {
tables: [User.tableModel, Group.tableModel, UserGroupMapping.tableModel],
},
});
<!--NeedCopy-->