What It Is
Roles are ServiceNow's fundamental permission containers that define what users can see, access, and modify within the platform. They solve the core security problem of granular access control by grouping related permissions into logical units that can be assigned to users or groups. Unlike simple permission lists, roles can contain other roles through inheritance, creating hierarchical permission structures that mirror organizational authority levels. When a user attempts any action in ServiceNow—viewing a record, running a report, accessing a module—the platform evaluates their assigned roles against the required permissions to determine access.
Architecturally, roles live in the sys_user_role table within the System Security application, sitting at the platform layer alongside ACLs, user groups, and authentication mechanisms. The role system integrates directly with Access Control Lists (ACLs) through the Required role field on ACL records, creating the enforcement layer for role-based permissions. Role assignments are stored in sys_user_has_role (direct user assignments) and sys_group_has_role (group-based assignments), with role inheritance tracked in sys_user_role_contains relationships.
The data model execution happens through ServiceNow's security evaluation engine, which builds a complete role list for each user session by traversing direct assignments, group memberships, and role inheritance chains. This evaluation occurs at session establishment and gets cached until role assignments change or sessions expire. The platform maintains role effectiveness through Elevated privilege settings and Requires subscription flags that control when and how roles activate for users.
You cannot function without roles in any ServiceNow implementation beyond basic read-only access. Every module in the application navigator requires specific roles to appear in user menus. Every table operation—create, read, update, delete—depends on ACLs that reference required roles. Custom applications cannot enforce security without roles tied to their ACLs. Multi-tenancy, data segregation, and approval workflows all break without proper role-based access controls. Even basic reporting and dashboard access relies on roles like report_user or dashboard_viewer to function properly.
Platform owners create the foundational role structure during implementation, defining broad categories like itil, admin, and application-specific roles. System administrators manage day-to-day role assignments, create custom roles for business requirements, and maintain role inheritance hierarchies. Developers create roles for custom applications and integrate them with existing security models through proper ACL design. The relationship requires coordination—developers build the technical role requirements, admins implement the business logic, and platform owners maintain the overall security architecture.
Vancouver introduced role-based access improvements for Workspace and Service Portal, requiring new roles like workspace_user for proper functionality. Washington enhanced role caching and inheritance evaluation performance, reducing session establishment time for users with complex role hierarchies. Xanadu refined elevated privilege handling, making temporary role elevation more secure and auditable. Recent releases also improved role visibility in User Administration, showing inherited roles and their sources more clearly in the interface.
Where to Find and Configure It
Primary role configuration happens at System Security > Users and Groups > Roles where you create, modify, and organize roles. This interface shows role inheritance, assigned users and groups, and allows you to set role properties like Elevated privilege and Can delegate flags.
Role assignments are managed at System Security > Users and Groups > Users on the Roles tab for direct user assignments, or at System Security > Users and Groups > Groups on the Roles tab for group-based assignments. For bulk role management, use System Definition > Tables and navigate to sys_user_has_role or sys_group_has_role for direct table access.
In Studio and App Engine Studio, access role management through the Security section where you create application-specific roles and link them to ACLs. For scoped applications, roles created here are automatically prefixed with the application scope and isolated from global roles unless explicitly configured for cross-scope access. Role effectiveness appears in System Diagnostics > Session Debug under Security where you can see all active roles for the current user session and their inheritance chain.
How It Works Step by Step
Role evaluation happens during user session establishment and permission checks throughout platform interaction. When a user logs in, ServiceNow queries sys_user_has_role for direct assignments, then queries sys_user_grmember for group memberships and their associated roles from sys_group_has_role. The platform then follows sys_user_role_contains relationships to build the complete inherited role list, creating a flattened permissions cache for the session.
During runtime, every protected resource access triggers an ACL evaluation that compares the user's cached role list against the ACL's Required role field. The platform uses role matching logic that accounts for role inheritance—if a user has a parent role that contains the required role, access is granted. Role-based module visibility works similarly, with application navigator items checking role requirements before displaying in user menus.
Enjoying this? Get one deep-dive per week.
Join 1,000+ ServiceNow pros — scripts, GlideRecord patterns, Flow Designer techniques, and career moves. Free.
The Execution Order
- User authentication triggers session establishment
- System queries direct user role assignments from
sys_user_has_role - System queries user group memberships and their roles from
sys_group_has_role - Platform traverses role inheritance chains via
sys_user_role_containsrelationships - System flattens all roles into a single cached list for the session
- User requests resource access (table record, module, report)
- ACL engine compares cached user roles against required roles for the resource
- Access granted or denied based on role matching results
// Query to find all roles for a specific user including inheritance
var user = 'abel.tuter';
var userRoles = [];
// Get direct user role assignments
var directRoles = new GlideRecord('sys_user_has_role');
directRoles.addQuery('user.user_name', user);
directRoles.query();
while (directRoles.next()) {
userRoles.push(directRoles.getDisplayValue('role'));
}
// Get roles from group memberships
var groupRoles = new GlideRecord('sys_user_grmember');
groupRoles.addQuery('user.user_name', user);
groupRoles.query();
while (groupRoles.next()) {
var grpRoleGr = new GlideRecord('sys_group_has_role');
grpRoleGr.addQuery('group', groupRoles.getValue('group'));
grpRoleGr.query();
while (grpRoleGr.next()) {
userRoles.push(grpRoleGr.getDisplayValue('role'));
}
}
gs.info('User ' + user + ' has roles: ' + userRoles.join(', '));Real-World Scenarios
Creating Application-Specific Role Hierarchy for Custom HRSD
Your organization needs a custom HR Service Delivery application with three access levels: HR Specialists who can create and update all HR cases, HR Managers who can also approve requests and access reports, and HR Directors who have full administrative control. You need role inheritance so managers automatically get specialist permissions without duplicate assignments.
// Create base HR role
var hrSpecialist = new GlideRecord('sys_user_role');
hrSpecialist.initialize();
hrSpecialist.setValue('name', 'x_custom_hr.specialist');
hrSpecialist.setValue('description', 'HR Specialist - Create and update HR cases');
hrSpecialist.insert();
var specialistSysId = hrSpecialist.getUniqueValue();
// Create HR Manager role
var hrManager = new GlideRecord('sys_user_role');
hrManager.initialize();
hrManager.setValue('name', 'x_custom_hr.manager');
hrManager.setValue('description', 'HR Manager - Includes specialist + approvals + reports');
hrManager.insert();
var managerSysId = hrManager.getUniqueValue();
// Create HR Director role
var hrDirector = new GlideRecord('sys_user_role');
hrDirector.initialize();
hrDirector.setValue('name', 'x_custom_hr.director');
hrDirector.setValue('description', 'HR Director - Full HR application admin');
hrDirector.insert();
var directorSysId = hrDirector.getUniqueValue();
// Set up inheritance: Manager contains Specialist
var mgr_spec = new GlideRecord('sys_user_role_contains');
mgr_spec.initialize();
mgr_spec.setValue('role', managerSysId);
mgr_spec.setValue('contains', specialistSysId);
mgr_spec.insert();
// Set up inheritance: Director contains Manager (which inherits Specialist)
var dir_mgr = new GlideRecord('sys_user_role_contains');
dir_mgr.initialize();
dir_mgr.setValue('role', directorSysId);
dir_mgr.setValue('contains', managerSysId);
dir_mgr.insert();After creating this hierarchy, ensure your ACLs reference the appropriate role level—use x_custom_hr.specialist for basic table access since inheritance will grant access to managers and directors automatically. Watch for role name conflicts if you're working in a scoped application—the scope prefix gets added automatically. Test inheritance by assigning only the director role to a user and verifying they can perform specialist-level actions.
Implementing Temporary Elevated Access with Role-Based Approval
Your security team requires that certain administrative actions need temporary role elevation that expires after 4 hours and requires manager approval. Users should request security_admin access through a catalog item, get approval, receive the role temporarily, and have it automatically revoked.
Configure the security_admin role with Elevated privilege checked, create a Service Catalog item for role requests with approval workflow, and build a scheduled job to revoke expired elevated roles. In the catalog item's workflow, add a Run Script activity that creates the role assignment with an expiration timestamp stored in a custom field. Create a scheduled script execution that runs every hour to query and remove expired elevated role assignments.
Elevated privilege roles bypass some ACL evaluations, so test thoroughly in a sub-production instance. Users with elevated roles can potentially access records and perform actions that normal ACLs would block.
Segregating Multi-Tenant Data Access Through Geographic Roles
Your company operates in multiple countries with strict data residency requirements where users can only access incident records for their assigned geographic region. Each region needs separate roles that control data visibility, with some global administrators who can see all regions.
Create geographic roles like incident_user_na, incident_user_eu, and incident_user_apac along with a incident_user_global role that contains all regional roles. Build ACLs on the Incident table with script conditions that check both the user's role and a Region field on incident records. Add the region value to incident records through business rules or during creation workflows, ensuring data is properly tagged for access control.
Pay attention to report and dashboard access, which may show aggregate data across regions if not properly secured with the same role-based filtering. Domain separation might be a better architectural choice for strict multi-tenancy, but role-based segregation works well for softer regional boundaries. Test cross-region reference fields carefully, as related record access can inadvertently expose data from other regions.
The Classic Mistake
Granting the admin role directly to business users instead of creating specific functional roles with precise ACL controls.
The most destructive pattern happens when admins take shortcuts by assigning powerful roles like admin, itil, or user_admin directly to users who need specific access. A common example: HR needs to manage user records, so an admin assigns the user_admin role. Another frequent mistake is creating a "super user" by stacking multiple high-privilege roles like itil + admin + import_admin on a single service account. Even worse is when someone assigns the security_admin role to department leads "just in case they need emergency access."
This fails because ServiceNow's role engine uses additive permissions—once a user has any role that grants access, they get that access regardless of other restrictions. Users suddenly see tables they shouldn't (sys_user_role, sys_security_acl), can modify system configurations, or bypass workflow approvals entirely. The user_admin role includes write access to sys_user_grmember and sys_user_role tables, meaning HR can accidentally grant themselves admin privileges. It's non-obvious because the UI doesn't warn you about inherited permissions from powerful base roles.
// GOOD: Create specific functional role
// Role: hr_user_manager
// Description: Limited HR user management capabilities
// Role contains these specific roles:
// - personalize_choices (for user preference management)
// - report_reader (for basic reporting)
// Create targeted ACLs instead of broad permissions:
// Table: sys_user
// Operation: read,write
// Role: hr_user_manager
// Condition: gs.hasRole('hr_user_manager') && current.department == 'HR'
// Table: sys_user_grmember
// Operation: read,write
// Role: hr_user_manager
// Condition: gs.hasRole('hr_user_manager') && current.group.name.startsWith('HR')
// Never assign: user_admin, admin, itil to business usersCreate roles by function, not by convenience. If someone needs 3 different types of access, create 3 specific roles and assign all 3—never use one overprivileged role to cover multiple needs.
When to Use This vs Alternatives
Roles are the primary access control mechanism when you need to grant broad, functional permissions across multiple tables and operations. Use roles when access patterns follow job functions—incident managers need to read/write incidents, change approvers, and access knowledge articles. Groups handle team-based record ownership, but roles handle what actions those team members can actually perform.
When Roles Are the Right Choice
Choose roles when permissions span multiple applications or when you need consistent access across related tables. A change_manager role should grant access to change_request, change_task, cmdb_ci, and related approval workflows. Groups can't provide this cross-application access pattern, and individual ACLs would create maintenance nightmares. Roles also enable delegation—you can grant user_admin to department leads for localized user management that groups simply can't accomplish.
When to Use Groups Instead
Use groups when access is about record ownership and assignment, not functional capabilities. Groups excel at "who can see records assigned to my team" scenarios—the Service Desk group should see incidents assigned to them, but their ability to resolve those incidents comes from their itil role. Groups also handle approval chains and automatic assignment rules where roles are irrelevant. If you're setting up notification schemes or workflow routing based on organizational structure, groups are the correct mechanism.
When You Need Both Working Together
Most real implementations require both—groups define the organizational boundaries while roles define functional permissions within those boundaries. A user needs group membership in "Network Operations" to see network-related incidents assigned to their team, plus the itil role to actually resolve those incidents. The ACL condition becomes gs.hasRole('itil') && current.assignment_group.getRefRecord().hasRole('network_ops'). This pattern prevents the common mistake of creating overly broad roles or overly restrictive group-only access controls.
Platform Interactions & Side Effects
- ACL evaluation engine caches role memberships in session state—role changes don't take effect until logout/login or session timeout
- Business Rules checking
gs.hasRole()execute before ACL evaluation, so role-based BR conditions can override table-level ACL denials - Update Sets capture role assignments to
sys_user_roletable but NOT role hierarchy changes insys_user_role_contains—causes broken deployments - Notification filters using
gs.hasRole()in Advanced Conditions fail silently when roles contain special characters or spaces - Domain separation creates separate
sys_user_rolerecords per domain—same role name can have different permissions across domains - Transform Maps ignore role-based ACLs during import—data can be inserted into restricted tables if the transform user has
import_adminrole - Scheduled Jobs inherit roles from the user account running them—
adminrole bypasses all ACL restrictions in background scripts - REST API calls check roles before processing—insufficient roles return 403 Forbidden rather than 401 Unauthorized
- Role inheritance is calculated at login and stored in
user_session_statetable—nested role changes require session refresh to activate - Impersonation preserves original user's roles plus adds target user's roles—creates unexpected permission escalation
Debugging and Troubleshooting
Role permission failures typically manifest as users seeing "You do not have permission to read this record" messages or missing menu items and modules they should have access to. The most common symptom is inconsistent access—users can create records but can't read them afterward, or they can access a form through direct link but can't see the list view. Performance problems occur when role checks in ACLs involve complex conditions or database queries, causing slow page loads and form rendering delays.
Check System Logs > System Log > All for ACL evaluation failures and security violations. The Security Debug module (System Security > Debug Security) provides real-time ACL rule evaluation when enabled via glide.security.debug=true system property. Look for "Access denied by ACL" entries in logs and "Security: no ACL grants access" debug messages. The sys_user_role_grmember and sys_user_grmember tables show the actual role and group assignments that ACL evaluation uses.
Common error messages include "Invalid table" (role lacks read access to the table), "Field security does not permit read" (field-level ACL denial), and "Security constraints restrict this operation" (role-based business rule blocking action). JavaScript errors like "ReferenceError: current is not defined" in role condition scripts indicate ACL context problems. The Role Inspector module shows inherited permissions but may not reflect current session state if roles changed recently without logout/login.
Diagnostic Checklist
- Verify actual role assignments in
User Administration > Users→ user record → Roles tab, not just group memberships - Enable
glide.security.debugand test the failing operation to see ACL evaluation details - Check role hierarchy by querying
sys_user_role_containstable for nested role relationships - Test with elevated privileges (admin user) to confirm whether issue is role-related or application bug
- Review ACL records for the specific table/operation using
System Security > Access Control Rules - Clear user session state by having user logout/login or using
gs.getSession().invalidate()in Scripts - Background - Validate domain separation settings if using multiple domains—check
Domainfield on role records
Quick Reference
- Maximum role nesting depth is 10 levels—deeper hierarchies cause evaluation timeouts and session errors
- Role names are case-sensitive in
gs.hasRole()calls but not in ACL role field assignments - The
snc_internalrole bypasses ALL ACL restrictions including field-level security—never assign to regular users - Role inheritance calculations are cached for 20 minutes—changes to
sys_user_role_containshave delayed effect - Assigning
adminrole to a group automatically grants it to all current AND future group members - REST API table access requires both role permissions AND
web_service_access_only=falseon the user record - Deactivated roles remain in
sys_user_role_grmembertable but don't grant permissions—causes confusing Role Inspector displays - Global Update Sets don't capture role assignments made through
User Administrationinterface—only direct table modifications - Role conditions execute as the user requesting access, not as admin—
gs.getUser()returns the actual user, not system account - The
elevated_rolessystem property controls whether users can escalate privileges through UI actions—default is false