Accessing and managing users

Managing accounts that will access an organization is a key aspect of a Web GIS deployment. Specific management for accounts varies depending upon a specific organization's identity store. The API for Python provides functionality for managing user accounts. Automating management tasks such as provisioning licenses, privileges, creating and removing user accounts can save a great deal of time. The gis module provides you with User and UserManager classes to respresent users as objects and help you accomplish the most common tasks.

As you might have observed, the API utilizes manager classes accessible from a GIS object through properties. For example, an instance of the ContentManager class is returned when accessing the content property on a GIS object. The GIS object employs a users property to access the UserManager] class for managing operations and properties of User objects in the organization. This pattern of using properties to access specific manager classes is typical throughout the ArcGIS API for Python. Often times in guides and samples, these properties are chained together to decrease code complexity in accessing specific methods.

Let's explore using the API for managing users within a GIS organization. For additional resources to explore options for configuring users within a Web GIS deployment and the differences inherent in using different organizational deployments, see:

About your account

Let's connect to an organization and explore properties of our user account before moving on to administering other user accounts. We'll import the GIS class from gis module and connect to an ArcGIS Enterprise:

from arcgis.gis import GIS
gis = GIS(profile="your_online_profile")

You can access your user account by accessing the me property as shown below:

me = gis.users.me
me
ArcGIS Python

Bio: ArcGIS Python public account. Please do not change the profile information.
First Name: ArcGIS
Last Name: Python
Username: arcgis_python
Joined: December 23, 2016

Similar to Item objects, when using the Jupyter notebook IDE, you can visualize User objects in rich HTML representation with thumbnails and attribute information.

Properties of a User object

You can query much more information about the user account as properties on the User object.

Consult the API User class reference documentation for a complete listing of properties available on a registered account through the Python API. In addition, the REST API User resource documentation provides a comprehensive table of details returned in the response to a request of this resource.

Let's explore some user properties:

me.access
'public'

You can query a user object's lastLogin property to explore when the user last connected and compare that to the created property to determine any actions to take on whether the account should be deleted or the account owner contacted:

import time
# convert Unix epoch time to local time
created_time = time.localtime(me.created/1000)
print("Created: {}/{}/{}".format(created_time[0], created_time[1], created_time[2]))

last_accessed = time.localtime(me.lastLogin/1000)
print("Last active: {}/{}/{}".format(last_accessed[0], last_accessed[1], last_accessed[2]))
Created: 2016/12/23
Last active: 2023/7/26

Let us print some more information about this account

print(f"Description")
print(f"{me.description}")
Description
ArcGIS Python public account.

Please do not change the profile information.
print(f"Email{' '*12}First Name{' '*5}Last Name{' '*6}Full Name{' '*6}Level  MultiFactor{' '*4}Provider{' '*2}User Type")
print(f"\n{me.email:17}{me.firstName:15}{me.lastName:15}{me.fullName:15}{me.level:^7}{me.mfaEnabled:^15}{me.provider:10}{me.userType}")
Email            First Name     Last Name      Full Name      Level  MultiFactor    Provider  User Type

rsingh@esri.com  ArcGIS         Python         ArcGIS Python     2          0       arcgis    arcgisonly

You can determine how much storage is being used by this account

quota = me.storageQuota
used = me.storageUsage
pc_usage = round((used / quota)*100, 2)
print("Usage: " + str(pc_usage) + "%")
Usage: 9.04%

You can determine the groups the user is a member of:

user_groups = me.groups
print("Member of " + str(len(user_groups)) + " groups")

# groups returned with rich HTML display in a notebook
user_groups[0]
Member of 272 groups
Gallery

Summary: Content in this group appears on the organization gallery.
Description: This group contains a collection of maps, apps and mobile configurations highlighted in the organization's gallery.
Owner: arcgis_python
Created: February 15, 2017

Searching for user accounts

The search() method on the UserManager class provides the means to locate specific users in the organization. The query parameter accepts standard ArcGIS REST API criteria to explore the full-featured text search engine of the organization. Consult the Search Reference for full technical details to help set expections for results and understand how the search operation behaves. Specific user search documentation will also help you determine how to construct a query argument to satisfy your needs. To illustrate searching, let us connect as an organization administrator and search ArcGIS Online as there are many more users available there.

ago_gis = GIS(profile="your_online_admin_profile")
# search the users whose username begins with _Esri_Curator_
esri_curator_accounts = ago_gis.users.search(query="username:Esri_Curator*", max_users=25, outside_org=True)
len(esri_curator_accounts)
17

NOTE: The max_users argument by default is set to 100 and can be modified. Responses are limited to 10,000 results per query. See Web GIS Considerations and limitations for full details. To return more than 10,000 users, create a query argument using search filters and append results to a list to get the entire set of results.

Each element in the list returned is a User object that you can query.

esri_curator_accounts
[<User username:Esri_Curator_Basemaps>,
 <User username:Esri_Curator_Boundaries>,
 <User username:Esri_Curator_CR>,
 <User username:Esri_Curator_Demographic>,
 <User username:Esri_Curator_DK>,
 <User username:Esri_Curator_EarthObs>,
 <User username:Esri_Curator_ES>,
 <User username:Esri_Curator_GL>,
 <User username:Esri_Curator_Historical>,
 <User username:Esri_Curator_IE>,
 <User username:Esri_Curator_Imagery>,
 <User username:Esri_Curator_KR>,
 <User username:Esri_Curator_Landscape>,
 <User username:Esri_Curator_Oceans>,
 <User username:Esri_Curator_SR>,
 <User username:Esri_Curator_Transport>,
 <User username:Esri_Curator_Urban>]
esri_curator_accounts[0]
Esri Curator for Basemaps

Bio: This account is managed by Esri, Inc. staff and used to curate Basemap content for the Living Atlas of the World. To nominate your content for the Living Atlas, please visit livingatlas.arcgis.com/contribute. To contact the Esri Curators, please email curatelivingatlas@esri.com.
First Name: Esri Curator
Last Name: for Basemaps
Username: Esri_Curator_Basemaps
Joined: March 31, 2015

Once you know a user's username, you can access that object using the get() method. Let us access the Esri curator account for historical maps

esri_curator_bmaps = ago_gis.users.get(username='Esri_Curator_Historical')
esri_curator_bmaps
Esri Curator for Historical Maps

Bio: This account is managed by Esri, Inc. staff and used to curate Historical Map content for the Living Atlas of the World. To nominate your content for the Living Atlas, please visit livingatlas.arcgis.com/contribute. To contact the Esri Curators, please email curatelivingatlas@esri.com.
First Name: Esri Curator
Last Name: for Historical Maps
Username: Esri_Curator_Historical
Joined: March 31, 2015

Creating new user accounts

You can add new users to an organization with two UserManager methods, signup() or create(). The signup() method only works for adding built-in accounts to an ArcGIS Enterprise deployment. It will not work with an organization deployed on ArcGIS Online. Unlike the create() method, signup() does not require administrator privileges.

Note, you can disable self-signup in your ArcGIS Enterprise which would render the signup() unusable if you want to configure organization access in an invite-only manner.

You need administrator privileges to call the create() method. With an ArcGIS Enterprise administrator account, you can use this method to add both built-in user accounts (provider="arcgis") and organization-specific identity store accounts (provider="enterprise"). For an ArcGIS Online organization, you can only create users that use the built-in credential store. For built-in accounts, you provide an explicit password when the account is created, which the user can subsequently change upon login. For enterprise accounts using your organization-specific identiy store credentials, you can ignore the password parameter and your users will authenticate through that identity store. See the understanding identity stores documentation for details on configuring an organization for access.

What any new user can do is based upon the privileges assigned through the role and user type arguments of the create() operation. See the User types, roles, and privileges documentation for detailed descriptions on how these elements work together. A set of privileges is assigned to a role, and then based upon those privileges a role will be compatible with certain user_types. Together these values determine what tasks and workflows a user can perform in an organization.

The user_type and role arguments are required when running the method unless they have been configured through new member defaults. See the Configure new member defaults documentation for detailed instructions on how to set these values. The UserManager provides the user_settings property which allows administrators to both get and set these default values.

Let us look at some examples of creating users:

Create user using new member default values

The ago_gis connection currently represents a default administrator role connecting to ArcGIS Online. Let's first examine whether New member defaults have been configured:

new_member_defaults = ago_gis.users.user_settings
new_member_defaults
{'role': 'org_publisher',
 'userLicenseType': 'advancedUT',
 'groups': ['96c9a826e654481ba2cf8f6d04137b32'],
 'userType': 'arcgisonly',
 'apps': [],
 'appBundles': [],
 'categories': []}

Note: The userLicenseType key refers to the user_type parameter, and the userType key refers to the provider parameter.

# Create an ArcGIS Online account using `New Member Defaults`
demo_user1 = ago_gis.users.create(username = 'new_uq_user_A9b4K1',
                                  password = 'Ready4W8bGI$',
                                  firstname = 'demo',
                                  lastname = 'user',
                                  email = 'python@esri.com',
                                  description = 'Demonstrating how to create users using ArcGIS Python API')
demo_user1
demo user

Bio: None
First Name: demo
Last Name: user
Username: new_uq_user_A9b4K1
Joined: July 26, 2023

We can examine that the new user has been assigned the default values:

print(f"New user: {demo_user1.username}\n{'-'*50}")
print(f"{' '*2}role:{' '*10}{demo_user1.role}")
print(f"{' '*2}user type:{' '*5}{demo_user1.userLicenseTypeId}")
New user: new_uq_user_A9b4K1
--------------------------------------------------
  role:          org_publisher
  user type:     advancedUT

Note: We did not enter a value for the provider argument but rather accepted the default arcgis because the organization we're connected to utilizes built-in user security. If we were creating accounts for an organization employing an organization-specific identity store, we would specify the provider argument as enterprise and enter an idpUsername argument as well to specify the account's username within that credential store. To learn more about this configuration, refer to this Understand identity stores help topic.

More about user roles

We briefly discussed how to determine what a user can do within an organization in a preceding paragraph when we talked about user types, roles, and privileges. Specifically, the member roles define a set of privileges. The role can then be assigned to a user as we've demonstrated above. An organization provides default roles upon installation or subscription activation. See

These default roles are configured with a set of privileges that cannot be changed. Depending upon the needs and security of your organization, you can however create custom roles. Depending upon the organizational deployment type, you may choose to use ArcGIS Online templates or ArcGIS Enterprise templates as a starting point for other roles, or construct specialized roles from scratch based on what your organization wants users to accomplish.

To see the role for any User object, you can query the role property as previously seen:

demo_user1_role = demo_user1.role
print(type(demo_user1_role))
print(demo_user1_role)
<class 'str'>
org_publisher

Since this user was created with a built in role specified as a string, we get back a string with value org_publisher.

Creating a new role

Let's create a new role in the organization. Use the create() method on the RoleManager class for this task. Specifically, we want a role to assign to users who we want to only publish tile layers. The role should have a subset of privileges of the default User role and be able to create items, publish tile layers, join groups, and view and share items to the organization. This role will not have any administrator privileges. Let's demonstrate how to create a role. In order to assign privileges to a role, let's examine the exact syntax format for individual privileges using the privileges property on our user object:

Note: Even though privileges is not technically a property of the User class, once a user object is initialized, the individual privileges from the role hydrate the user object.

To use the API to set privileges, we need to know the syntax of an individual privilege. Each privilege will follow this basic structure:

*:<role>:*

For example, the user privilege to create and manage their own groups is called portal:user:createGroup. As noted above, you can observe the specific privileges of a user by querying the privileges property. For the demo_user1 user we created above, we can see a sample of the syntax for the privileges from the role assigned to that user by looking at the first 10 privilges:

demo_user1.privileges[:10]
['features:user:edit',
 'portal:publisher:bulkPublishFromDataStores',
 'portal:publisher:createDataPipelines',
 'portal:publisher:publishDynamicImagery',
 'portal:publisher:publishFeatures',
 'portal:publisher:publishKnowledgeGraph',
 'portal:publisher:publishScenes',
 'portal:publisher:publishServerServices',
 'portal:publisher:publishTiledImagery',
 'portal:publisher:publishTiles']

For the custom role we want to create, we'll construct a list of specific privileges to provide the ability to publish tile layers, join and create a group as well as view and share items in the organization. We'll then create a new role called tiles_publisher in the organization.

Note: the privileges parameter was provided a list of strings specifying each individual privilege. Refer to the privileges property on the Role class to see a comprehensive list of possible privileges.

# create a tiles publisher role
privilege_list = ["portal:publisher:publishTiles",
                  "portal:user:createItem",
                  "portal:user:joinGroup",
                  "portal:user:viewOrgGroups",
                  "portal:user:viewOrgItems",
                  "portal:user:shareToGroup",
                  "portal:user:shareToOrg",
                  "portal:user:createGroup",
                  "portal:user:shareGroupToOrg"
                 ]

tiles_pub_role = ago_gis.users.roles.create(name = 'tiles_publisher',
                                            description = 'User that can publish tile layers',
                                            privileges = privilege_list)

tiles_pub_role
<Role name: tiles_publisher, description: User that can publish tile layers>
# inspect the privileges of this role
tiles_pub_role.privileges
['portal:publisher:publishTiles',
 'portal:user:createGroup',
 'portal:user:createItem',
 'portal:user:joinGroup',
 'portal:user:shareToGroup',
 'portal:user:shareToOrg',
 'portal:user:shareGroupToOrg,
 'portal:user:viewOrgGroups',
 'portal:user:viewOrgItems']

Creating a user with values other than new member defaults

Let's first return a list of possible values we can enter in for the user_type argument. The license_types property on the UserManager returns a dictionary with comprehensive information about each license type. We're only interested in the specific id value so we'll use a list comprehension to return a list of possble values to use as user_type arguments:

usr_types = [ut['id'] for ut in ago_gis.users.license_types]
usr_types
['advancedUT',
 'basicUT',
 'creatorUT',
 'editorUT',
 'fieldWorkerUT',
 'GISProfessionalAdvUT',
 'GISProfessionalBasicUT',
 'GISProfessionalStdUT',
 'IndoorsUserUT',
 'insightsAnalystUT',
 'liteUT',
 'standardUT',
 'storytellerUT',
 'viewerUT']

Listing all the custom roles in an org

Next, let's inspect the possible values we can use for the role argument. The default Administrator, Publisher, and User roles (see Default roles for descriptions) are available by using org_admin, org_publisher, or org_user values as role arguments. To assign other default roles or custom roles, the values to use for the role argument are the role_id values returned from the all() method of the RoleManager class. We can access a RoleManager object using the roles property on the UserManager:

role_mgr = ago_gis.users.roles
print(f"Role:{' '*20}Role_id{' '*14}\n{'-'*21}{' '*4}{'-'*16}")
for role in role_mgr.all():
    print(f"{role.name:24} {role.role_id:22}")
Role:                    Role_id              
---------------------    ----------------
Viewer                   iAAAAAAAAAAAAAAA      
Data Editor              iBBBBBBBBBBBBBBB      
Facilitator              iCCCCCCCCCCCCCCC      
Analyst                  53JTWAmyPz3MLgwl      
role_6f33c               8MueSvFrA35xyg5p      
AGOLImageryAnalysis      bl8ksdIBpwV4pa1N      
AllNotebookPrivileges    cMH6sh9YL5RNFtat      
UC2018_GEOG471           DmZ9fQYjofiNtJWn      
tiles_publisher          gBC4ANXsKok12Lm4      
guest_notebooks_basic    o4mDG5PEwU2y7tlv      
advanced notebooks       PAH6xJAmWgYuF2vX      

We can see the role_id value for the custom role we created. Let's use that id to create a new user and assign that user to this new role:

tiles_pub_user = ago_gis.users.create(username='tiles_publisher_1',
                                      password = 'b0cb0c9f63e',
                                      firstname = 'Tiles',
                                      lastname = 'Publisher',
                                      email = 'python@esri.com',
                                      description = 'Custom role, can only publish tile layers',
                                      role = 'gBC4ANXsKok12Lm4',
                                      user_type='GISProfessionalAdvUT')

tiles_pub_user
Tiles Publisher

Bio: None
First Name: Tiles
Last Name: Publisher
Username: tiles_publisher_1
Joined: July 26, 2023

Querying the privileges property of a User object returns a list of strings with fine grained privileges. When creating a Role object, you can pick and choose from this or refer to the api ref doc.

tiles_pub_user.privileges
['portal:publisher:publishTiles',
 'portal:user:createGroup',
 'portal:user:createItem',
 'portal:user:joinGroup',
 'portal:user:shareToGroup',
 'portal:user:viewHostedFeatureServices',
 'portal:user:viewOrgGroups',
 'portal:user:viewOrgItems']

Querying the roleId property of a User returns you the custom roles' ID. You can use this to search for that role to know more details or create another user with the same role:

tiles_pub_user.roleId
'gBC4ANXsKok12Lm4'
searched_role = gis.users.roles.get_role(tiles_pub_user.roleId)
searched_role.description
'User that can publish tile layers'

Deleting user accounts

Provided you are logged in as an administrator, you can delete user accounts by calling the delete() method on a User object.

Note: You can also use the delete_users() method in the arcgis.gis.admin submodule to delete a list of users.

The Web GIS prevents you from deleting users if they own items and/or groups. It is important to query a user to investigate whether they own content.

Accessing user content

As an administrator, you can view the folders and items owned by any user. Get the User object and then query the items() method and folders property.

pub1_user = ago_gis.users.get("publisher1_uq")

List the folders owned by a user

publisher_folder_list = pub1_user.folders
publisher_folder_list
[{'username': 'publisher1_uq',
  'id': '01bf52ddd49b45caa9c5a6ef263d8352',
  'title': 'Arkansas data',
  'created': 1690416367000},
 {'username': 'publisher1_uq',
  'id': 'b73d3fd029a14fcda72ba1af8fdbdd3c',
  'title': 'chicago_data',
  'created': 1690415221000},
 {'username': 'publisher1_uq',
  'id': 'ff046ef454c04788b53b96261d5803ef',
  'title': 'historical_data',
  'created': 1690415732000}]

List the content in a user's root folder

In addition to folder a user may have created, each user also has a root folder that contains those items that have not been explicitly added to a folder:

publisher1_root_folder_items = pub1_user.items()
print("Total number of items in root folder: " + str(len(publisher1_root_folder_items)))

#access the first item for a sample
publisher1_root_folder_items[0]
Total number of items in root folder: 3
Colorado Mountain Peaks
Data about peaks in the Rocky Mountains of Colorado.Shapefile by publisher1_uq
Last Modified: July 26, 2023
0 comments, 1 views
# list all items for the user
print(f"Root folder: {pub1_user.username}")
print(f" Item Title{' '*22}Item Type{' '*16}\n {'-'*27}{' '*5}{'-'*25}")
for root_item in publisher1_root_folder_items:
    print(f" {' '*1}{root_item.title:31}{root_item.type:25}")
print("\n")
for pub_folder in publisher_folder_list:
    print(f"Folder: {pub_folder['title']}")
    print(f" Item Title{' '*22}Item Type{' '*16}\n {'-'*27}{' '*5}{'-'*25}")
    for folder_item in pub1_user.items(folder=pub_folder['title']):
        print(f" {' '*1}{folder_item.title:31}{folder_item.type:25}")
    print("\n")
Root folder: publisher1_uq
 Item Title                      Item Type                
 ---------------------------     -------------------------
  Colorado Mountain Peaks        Shapefile                
  Colorado Mountain Peaks        Feature Service          
  World Country Boundary Data    Service Definition       


Folder: Arkansas data
 Item Title                      Item Type                
 ---------------------------     -------------------------
  AR Boundaries                  Shapefile                
  AR Boundaries                  Feature Service          


Folder: chicago_data
 Item Title                      Item Type                
 ---------------------------     -------------------------
  Chicago Accidents              CSV                      
  Chicago Accidents              Feature Service          
  Chicago Accidents Volume2      CSV                      
  Chicago Accidents Volume2      Feature Service          


Folder: historical_data
 Item Title                      Item Type                
 ---------------------------     -------------------------
  Ancient Woodland Inventory UK  Shapefile                
  Ancient Woodland Inventory UK  Feature Service          


As an administrator within an organizaion, you are able to query the contents of another user without knowing that user's password or logging in as that user.

Reassigning user content

When the time comes to delete a user account, you can filter these items and choose to preserve some and delete the content that is no longer needed. We're going to delete the publisher1_uq account we've just looked at, keeping only some accident data we plan to analyze later.

Note: It is import to consider the privileges of each user. If the receiving user does not have the proper permissions to be reassigned an item, errors may occur.

Note: If an item's sharing level is private but shared with groups, the receiving user must have the appropriate sharing access to all groups the item is shared with.

We'll reassign the source Feature Layer items about accidents in Chicago to the tiles_pub_user user we created earlier. We'll use the advanced_search() method to query for specific item titles and types, and reassign these items. You can reassign specific items to another user by calling the reassign_to() method on the Item object.

chi_flyr_items = ago_gis.content.advanced_search(query=f"owner:{pub1_user.username} title:Chicago type:Feature Service", )["results"]
chi_flyr_items
[<Item title:"Chicago Accidents" type:Feature Layer Collection owner:publisher1_uq>,
 <Item title:"Chicago Accidents Volume2" type:Feature Layer Collection owner:publisher1_uq>]
for flyr_item in chi_flyr_items:
        flyr_item.reassign_to(target_owner=tiles_pub_user)

Let's now query the tiles_pub_user to verify the items were successfully assigned.

tiles_pub_user.items()
[<Item title:"Chicago Accidents" type:CSV owner:tiles_publisher_1>,
 <Item title:"Chicago Accidents" type:Feature Layer Collection owner:tiles_publisher_1>,
 <Item title:"Chicago Accidents Volume2" type:CSV owner:tiles_publisher_1>,
 <Item title:"Chicago Accidents Volume2" type:Feature Layer Collection owner:tiles_publisher_1>]

Notice how the related_items for the Feature Layer are automatically assigned as part of the operation.

Delete user and reassign items

Now we are left with a few more items which we want to reassign to a user named arcgis_python in our organization. We can call the reassign_to() method of the User object or we can call the delete() method on the User object and provide an argument to the reassign_to parameter to accomplish the same task. First let's take a look at the remaining items owned by the publisher1_uq user:

ago_gis.content.advanced_search(query=f"owner:{pub1_user.username}")
{'total': 7,
 'start': 1,
 'num': 100,
 'nextStart': -1,
 'results': [<Item title:"Ancient Woodland Inventory UK" type:Feature Layer Collection owner:publisher1_uq>,
  <Item title:"Ancient Woodland Inventory UK" type:Shapefile owner:publisher1_uq>,
  <Item title:"AR Boundaries" type:Feature Layer Collection owner:publisher1_uq>,
  <Item title:"AR Boundaries" type:Shapefile owner:publisher1_uq>,
  <Item title:"Colorado Mountain Peaks" type:Shapefile owner:publisher1_uq>,
  <Item title:"Colorado Mountain Peaks" type:Feature Layer Collection owner:publisher1_uq>,
  <Item title:"World Country Boundary Data" type:Service Definition owner:publisher1_uq>]}

Note: The advanced_search() method searches all folders owned by a user. When using the reassign_to parameter in the delete() method, the output items are stored in folders named after the original username followed by the folder title, including a folder named username_root for items that are stored in the original user's root folder.

Now we'll use the delete() method to remove the publisher1_uk user while reassigning their items:

pub1_user.delete(reassign_to='arcgis_python')
True

We'll search for the user to verify the deletion:

ago_gis.users.advanced_search(query=f"owner:{pub1_user.username}")
{'total': 0, 'start': 1, 'num': 10, 'nextStart': -1, 'results': []}

Thus, we have successfully deleted a user after taking care of that user's content.

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.