09-15-2023 04:51 PM
Use the JumpCloud API to configure and update both static user and device groups to dynamic groups. Dynamic Groups are groups with attribute-driven rules that allow membership to be either fully automated, or require a review prior to the membership change taking place.
Instead of the Admin Portal, JumpCloud admins can use this article to build automated workflows in the API around user and device group membership. Resultingly, all applied entitlements will automatically take effect, with or without review, and update group memberships without having to manually change group membership.
The following table shows which attributes, operators, and values are currently supported when configuring rules for a dynamic user group via memberQuery
.
Several of the attributes' valid values are free text fields, meaning that you can input any text string. Currently, there is no validation for the values when setting a rule with one of these attributes. The value used for the rule must match exactly what has been entered for the user in order for it to be returned in the query. Any invalid operator or value used via memberQuery
may return no result or an unexpected result.
Attribute |
Operators |
Valid Values |
|
|
free text field |
|
|
free text field |
|
|
free text field |
|
|
free text field |
|
|
free text field |
|
|
free text field |
|
|
free text field |
|
|
|
The following table shows which attributes, operators, and values are currently supported when configuring rules for a dynamic device group via memberQuery
.
Note that there is currently no validation for operators or valid values. Any invalid operator or value used via memberQuery
may return no result or unexpected result.
Attribute |
Operators |
Valid Values |
|
|
|
|
|
|
|
|
|
|
|
Any valid numerical value. |
|
|
Any date adhering to ISO-8601 formatting standards. |
All of the dynamic groups-related API endpoint documentation can be found in the JumpCloud API (2.0) Documentation. User and device group endpoints are separate, and all dynamic group commands are in the context of either users or devices. There are no generic dynamic group endpoints that cover both users and devices.
The core components of dynamic group management on the API schema are:
STATIC
- All changes to membership are managed by the administrator. This is the default value.
DYNAMIC_REVIEW_REQUIRED
- JumpCloud will generate membership changes based on the group’s memberQuery
, memberQueryExemptions
, and current membership. The administrator must manually apply these suggestions to make membership changes.
DYNAMIC_AUTOMATED
- JumpCloud will generate and automatically apply membership changes based on the group’s memberQuery
, memberQueryExemptions
, and current membership
Determines how a group's membership is evaluated for a dynamic group. Current considerations to keep in mind when building a memberQuery
:
The only supported queryType
is FilterQuery
.
The filters
field contains an array of filters built using eligible attributes, operators, and values detailed in the section below.
Currently, all filter conditions are joined by an implicit and
operator.
The in
operator expects a pipe (|
) delimited list of values.
All values are provided as a string type.
For example, the following query
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "attribute1",
"operator": "eq",
"value": "1"
},
{
"field": "attribute2",
"operator": "in",
"value": "1|2|3"
}
]
would behave similar to this sql clause:
WHERE attribute1 = 1 AND attribute2 IN(1, 2, 3)
An array of GraphObjects exempted from the query. When evaluating membership, JumpCloud will never add or remove an exempt member from the group. Their membership status can only be maintained manually via the admin. An exemption consists of an objectId and a type, as in this example:
"memberQueryExemptions": [
{
"id": "633ddf437046a60780ce898e",
"type": "system"
}
],
Determines whether nightly emails are sent notifying the admin of any pending operations. This is only applicable for DYNAMIC_REVIEW_REQUIRED
groups.
The following sections are meant to provide examples of completing certain tasks related to Dynamic User Group configuration and management.
In this example, we are creating a new dynamic user group wherename
= groupUsingInOperatormembershipMethod
= DYNAMIC_REVIEW_REQUIRED
memberQuery
leverages several attributes in order to show how a complex filter can be used. In this example, we are filtering for members assigned to the Cost Centers 111, 222, and 333 whose department is Engineering.
POST https://console.jumpcloud.com/api/v2/usergroups
{
"name": "groupUsingInOperator",
"type": "user_group",
"description": "A group using in operator for membership query.",
"memberSuggestionsNotify": false,
"membershipMethod": "DYNAMIC_REVIEW_REQUIRED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "costCenter",
"operator": "in",
"value": "111|222|333"
},
{
"field": "department",
"operator": "eq",
"value": "Engineering"
}
]
}
}
Response 201
{
"attributes": {
"ldapGroups": [
{
"name": "groupUsingInOperator1"
}
]
},
"id": "{id}",
"name": "groupUsingInOperator",
"type": "user_group",
"email": "",
"description": "A group using in operator for membership query.",
"memberSuggestionsNotify": false,
"membershipAutomated": false,
"membershipMethod": "DYNAMIC_REVIEW_REQUIRED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "costCenter",
"operator": "in",
"value": "111|222|333"
},
{
"field": "department",
"operator": "eq",
"value": "Engineering"
}
]
},
"memberQueryExemptions": []
}
In this example, we are changing the membershipMethod
to DYNAMIC_AUTOMATED
in line 6 so that user group membership changes don’t have to be reviewed and will update automatically.
PUT https://console.jumpcloud.com/api/v2/usergroups/{id}
{
"name": "groupUsingInOperator",
"type": "user_group",
"description": "A group using in operator for membership query.",
"memberSuggestionsNotify": false,
"membershipMethod": "DYNAMIC_AUTOMATED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "costCenter",
"operator": "in",
"value": "111|222|333"
},
{
"field": "department",
"operator": "eq",
"value": "Engineering"
}
]
}
}
Response 201
{
"attributes": {
"ldapGroups": [
{
"name": "groupUsingInOperator"
}
]
},
"id": "{id}",
"name": "groupUsingInOperator",
"type": "user_group",
"email": "",
"description": "A group using in operator for membership query.",
"memberSuggestionsNotify": false,
"membershipAutomated": true,
"membershipMethod": "DYNAMIC_AUTOMATED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "costCenter",
"operator": "in",
"value": "111|222|333"
},
{
"field": "department",
"operator": "eq",
"value": "Engineering"
}
]
},
"memberQueryExemptions": []
}
In this example, we are changing the group with membershipMethod
set to DYNAMIC_REVIEW_REQUIRED
to not send email notifications when there are group membership suggestions need to be reviewed. Do this by setting memberSuggestionsNotify
in line 5 to false
.
PUT https://console.jumpcloud.com/api/v2/usergroups/{id}
{
"name": "groupUsingInOperator",
"type": "user_group",
"description": "A group using in operator for membership query.",
"memberSuggestionsNotify": false,
"membershipMethod": "DYNAMIC_REVIEW_REQUIRED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "costCenter",
"operator": "in",
"value": "111|222|333"
},
{
"field": "department",
"operator": "eq",
"value": "Engineering"
}
]
}
}
Response 201
{
"attributes": {
"ldapGroups": [
{
"name": "groupUsingInOperator"
}
]
},
"id": "{id}",
"name": "groupUsingInOperator",
"type": "user_group",
"email": "",
"description": "A group using in operator for membership query.",
"memberSuggestionsNotify": false,
"membershipAutomated": true,
"membershipMethod": "DYNAMIC_REVIEW_REQUIRED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "costCenter",
"operator": "in",
"value": "111|222|333"
},
{
"field": "department",
"operator": "eq",
"value": "Engineering"
}
]
}
}
In this example, we are (1) adding an exemption to the user group so that it is ignored by the query rules and (2) adding the user to the group. By adding the exemption, the user is not automatically added to/removed from the group. A second intentional step must be taken to add the user to the group.
First, retrieve the user id’s for the users you want to exempt.
The list API can be used to get the user id, as well as other user attributes, in order to add the user to the exemption list.
POST https://console.jumpcloud.com/api/systemusers
-d '{
"username":"{username}",
"email":"{email_address}",
"firstname":"{Name}",
"lastname":"{Name}"
}'
Response 201
{
"totalCount": 1,
"results": [
{
"account_locked": false,
"account_locked_date": null,
"activated": false,
"addresses": [],
"allow_public_key": true,
"alternateEmail": null,
"attributes": [],
"company": "value1",
"costCenter": "111",
"department": "",
"description": "example user",
"disableDeviceMaxLoginAttempts": false,
"displayname": "",
"email": "example@example.com",
"employeeIdentifier": null,
"employeeType": "Employee",
"enable_managed_uid": false,
"enable_user_portal_multifactor": false,
"external_dn": "",
"external_source_type": "",
"externally_managed": false,
"firstname": "",
"jobTitle": "dd",
"lastname": "",
"ldap_binding_user": false,
"location": "",
"managedAppleId": "",
"manager": null,
"mfa": {
"exclusion": false,
"configured": false
},
"middlename": "",
"password_never_expires": false,
"passwordless_sudo": false,
"phoneNumbers": [],
"samba_service_user": false,
"ssh_keys": [],
"state": "ACTIVATED",
"sudo": false,
"suspended": false,
"systemUsername": "",
"unix_guid": 5024,
"unix_uid": 5024,
"username": "exampleuser",
"created": "2022-09-21T19:44:59.329Z",
"organization": "{id}",
"password_expired": false,
"totp_enabled": false,
"_id": "{id}",
"id": "{id}",
"mfaEnrollment": {
"totpStatus": "NOT_ENROLLED",
"webAuthnStatus": "NOT_ENROLLED",
"pushStatus": "NOT_ENROLLED",
"overallStatus": "NOT_ENROLLED"
}
}
]
}
After the user ids are retrieved, users can be added to the exemption list by updating the corresponding user group. Update the existing dynamic user group by setting memberQueryExemptions
to an array of graph objects containing a user id and "type": "USER"
PUT https://console.jumpcloud.com/api/v2/usergroups/{id}
{
"name": "groupUsingInOperator",
"type": "user_group",
"description": "A group using in operator for membership query.",
"memberSuggestionsNotify": false,
"membershipMethod": "DYNAMIC_AUTOMATED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "costCenter",
"operator": "in",
"value": "111|222|333"
},
{
"field": "department",
"operator": "eq",
"value": "Engineering"
}
]
},
"memberQueryExemptions": [
{
"type": "USER",
"id": "{id}"
},
{
"type": "USER",
"id": "{id}"
}
]
}
Response 201
{
"attributes": {
"ldapGroups": [
{
"name": "groupUsingInOperator"
}
]
},
"id": "{id}",
"name": "groupUsingInOperator",
"type": "user_group",
"email": "",
"description": "A group using in operator for membership query.",
"memberSuggestionsNotify": false,
"membershipAutomated": true,
"membershipMethod": "DYNAMIC_AUTOMATED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "costCenter",
"operator": "in",
"value": "111|222|333"
},
{
"field": "department",
"operator": "eq",
"value": "Engineering"
}
]
},
"memberQueryExemptions": [
{
"type": "USER",
"id": "{id}"
},
{
"type": "USER",
"id": "{id}"
}
]
}
Once a user is exempted from the group, they can be manually added/removed as a member without risk of being “re-associated” because of the memberQuery
rules.
The following request adds the user to the group.
POST https://console.jumpcloud.com/api/v2/usergroups/{usergroup_id}/members
{
"op":"add",
"type":"user",
"id":"{user_id}"
}
Response 201
[]
The user will remain in the group until the admin removes them or the exemption is removed and the user no longer meets the memberQuery
rules for that group.
In this example, we are highlighting how to approve membership changes where the user group membershipMethod
is set to DYNAMIC_REVIEW_REQUIRED
.
First, the admin needs to retrieve suggestions. This will consist of an operation (add
or remove
) and a graph object.
GET https://console.jumpcloud.com/api/v2/usergroups/{id}/suggestions?skip=0&limit=50"
Response 201
[
{
"op": "add",
"object": {
"type": "user",
"id": "{id}"
}
},
{
"op": "remove",
"object": {
"type": "user",
"id": "{id}"
}
}
]
Once the object Ids are retrieved in the first step, the corresponding suggestions can be applied using below request. The request body contains an array of objectIds that have a pending suggestion.
POST https://console.jumpcloud.com/api/v2/usergroups/63371a4d89e58400010f1395/suggestions
{
"user_ids":[
"{id}",
"{id}"]
}'
Response 201
{
"object": {
"suggestions_found": [
"{id}",
"{id}"],
"suggestions_not_found": [
]
}
}
The response will contain any objectIds that did not contain a suggestion in. the suggestions_not_found
array. After the suggestions are retrieved, the admin can apply the suggestions that are found.
In this example, we are highlighting how to add another rule to an already existing dynamic user group by setting a new memberQuery
. In this case, we want users whose location is Colorado.
PUT https://console.jumpcloud.com/api/v2/usergroups/{id}
{
"name": "groupUsingInOperator",
"type": "user_group",
"description": "A group using in operator for membership query.",
"memberSuggestionsNotify": false,
"membershipMethod": "DYNAMIC_AUTOMATED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "costCenter",
"operator": "in",
"value": "111|222|333"
},
{
"field": "department",
"operator": "eq",
"value": "Engineering"
},
{
"field": "location",
"operator": "eq",
"value": "Colorado"
}
]
}
}
Response 201
{
"attributes": {
"ldapGroups": [
{
"name": "groupUsingInOperator"
}
]
},
"id": "{id}",
"name": "groupUsingInOperator",
"type": "user_group",
"email": "",
"description": "A group using in operator for membership query.",
"memberSuggestionsNotify": false,
"membershipAutomated": true,
"membershipMethod": "DYNAMIC_AUTOMATED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "costCenter",
"operator": "in",
"value": "111|222|333"
},
{
"field": "department",
"operator": "eq",
"value": "Engineering"
},
{
"field": "location",
"operator": "eq",
"value": "Colorado"
}
]
},
"memberQueryExemptions": []
}
The following sections provide examples of completing certain tasks related to dynamic device group configuration and management.
In this example, we are creating a new dynamic device group wherename
= Demo Dynamic GroupmembershipMethod
= DYNAMIC_REVIEW_REQUIRED
memberQuery
leverages several attributes in order to show how a complex filter can be used. In this example, we are filtering for all JumpCloud-supported devices minus Rocky Linux, of all valid architectures whose current version is greater than 9 whose device record was created on or after 09:20:36Z on July 10, 2020.
POST https://console.jumpcloud.com/api/v2/systemgroups
{
"name": "Demo Dynamic Group",
"membershipMethod": "DYNAMIC_REVIEW_REQUIRED",
"memberQuery":{
"queryType":"FilterQuery",
"filters":[
{
"field":"osFamily",
"operator":"in",
"value":"linux|darwin|windows|ios|android"
},
{
"field":"archFamily",
"operator":"in",
"value":"amd64|383|arm64|arm"
},
{
"field":"osVersionDetail.major",
"operator":"gt",
"value":"9"
},
{
"field":"created",
"operator":"ge",
"value":"2020-07-10 09:30:26Z"
},
{
"field":"os",
"operator":"ne",
"value":"Rocky"
}
],
]
}
}
Response: 201
{
"attributes": null,
"id": "{id}",
"name": "Demo Dynamic Group",
"type": "system_group",
"email": "",
"description": "",
"memberSuggestionsNotify": false,
"membershipAutomated": false,
"membershipMethod": "DYNAMIC_REVIEW_REQUIRED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "osFamily",
"operator": "in",
"value": "linux|darwin|windows|ios|android"
},
{
"field": "archFamily",
"operator": "in",
"value": "amd64|383|arm64|arm"
},
{
"field": "osVersionDetail.major",
"operator": "gt",
"value": "0"
},
{
"field": "created",
"operator": "ge",
"value": "2020-07-10 09:30:26Z"
},
{
"field": "os",
"operator": "ne",
"value": "Rocky"
}
]
},
"memberQueryExemptions": [
{
"type": "SYSTEM",
"id": "633ddf437046a60780ce898e"
}
]
}
In this example, we are changing the membershipMethod
to DYNAMIC_AUTOMATED
in line 3 so that device group membership changes don’t have to be reviewed and will update automatically.
PUT https://console.jumpcloud.com/api/v2/systemgroups/{id}
{
"name": "Demo Dynamic Group",
"membershipMethod": "DYNAMIC_AUTOMATED",
"memberQuery":{
"queryType":"FilterQuery",
"filters":[
{
"field":"osFamily",
"operator":"in",
"value":"linux"
}
]
}
}
Response: 200
{
"attributes": null,
"id": "{id}",
"name": "Demo Dynamic Group",
"type": "system_group",
"email": "",
"description": "",
"memberSuggestionsNotify": false,
"membershipAutomated": false,
"membershipMethod": "DYNAMIC_AUTOMATED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "osFamily",
"operator": "in",
"value": "linux"
}
]
},
"memberQueryExemptions": []
}
In this example, we are (1) adding an exemption to the group so that it is ignored by the query rules and (2) adding the device to the group. By adding the exemption, the device does not automatically get added to the group. A second intentional step must be taken to add the device.
To update the existing group, set memberQueryExemptions
to an the GraphObject with a system id and "type": "SYSTEM"
.
PUT https://console.jumpcloud.com/api/v2/systemgroups/{id}
{
"name": "Demo Dynamic Group",
"membershipMethod": "DYNAMIC_AUTOMATED",
"memberQuery":{
"queryType":"FilterQuery",
"filters":[
{
"field":"osFamily",
"operator":"in",
"value":"linux"
}
]
},
"memberQueryExemptions": [
{
"id": "633ddf437046a60780ce898e",
"type": "SYSTEM"
}
]
}
Response: 200
{
"attributes": null,
"id": "{id}",
"name": "Demo Dynamic Group",
"type": "system_group",
"email": "",
"description": "",
"memberSuggestionsNotify": false,
"membershipAutomated": true,
"membershipMethod": "DYNAMIC_AUTOMATED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "osFamily",
"operator": "in",
"value": "linux"
}
]
},
"memberQueryExemptions": [
{
"type": "SYSTEM",
"id": "633ddf437046a60780ce898e"
}
]
}
Once a device is exempted from the group, it can be manually added/removed as a member without risk of being “re-associated” because of the memberQuery
rules.
The following request adds the device to the group. The device will remain in the group until the admin removes it or the exemption is removed and the device no longer meets the FilterQuery
rules for the device group.
PUT https://console.jumpcloud.com/api/v2/systemgroups/{id}/members
{
"id": "633ddf437046a60780ce898e",
"op": "add",
"type": "system"
}
Response: 204
{}
In this example, we are highlighting how to approve membership changes where the device group membershipMethod
is set to DYNAMIC_REVIEW_REQUIRED
.
First, retrieve membership suggestions. This will consist of an operation (add
or remove
) and a graph object.
GET https://console.jumpcloud.com/api/v2/systemgroups/{id}/suggestions
Response: 200
[
{
"op": "add",
"object": {
"type": "system",
"id": "62e2d6c2a7bfcf8690f27254"
}
},
{
"op": "remove",
"object": {
"type": "system",
"id": "62e2d9b4a7bfcf68c0f2740c"
}
}
]
After the suggestions are retrieved, you can apply the suggestions. The request body contains an array of objectIds with a pending suggestion.
POST https://console.jumpcloud.com/api/v2/systemgroups/{id}/suggestions
{
"object_ids": [
"62e2d6c2a7bfcf8690f27254"
]
}
Response: 200
{
"object": {
"suggestions_found": [
"62e2d6c2a7bfcf8690f27254"
],
"suggestions_not_found": []
}
}
The response will contain any objectIds that did not contain a suggestion in the suggestions_not_found
array.
In this example, we are highlighting how to add another rule to an already existing dynamic device group by setting a new memberQuery
. In this example, we are adding a rule for macOS devices.
PUT https://console.jumpcloud.com/api/v2/systemgroups/{id}
{
"name": "Demo Dynamic Group",
"membershipMethod": "DYNAMIC_AUTOMATED",
"memberQuery":{
"queryType":"FilterQuery",
"filters":[
{
"field":"osFamily",
"operator":"in",
"value":"darwin"
}
]
}
}
Response: 200
{
"attributes": null,
"id": "{id}",
"name": "Demo Dynamic Group",
"type": "system_group",
"email": "",
"description": "",
"memberSuggestionsNotify": false,
"membershipAutomated": false,
"membershipMethod": "DYNAMIC_REVIEW_REQUIRED",
"memberQuery": {
"queryType": "FilterQuery",
"filters": [
{
"field": "osFamily",
"operator": "in",
"value": "darwin"
}
]
},
"memberQueryExemptions": []
}
I hope that this helps provide some guidance around leveraging the JumpCloud API to build automation leveraging the Dynamic Groups feature. As you experiment and build with this capability, please post here in the community what you have built and learned.
New to the site? Take a look at these additional resources:
Ready to join us? You can register here.