Showing posts with label ServiceNow Administration. Show all posts
Showing posts with label ServiceNow Administration. Show all posts

Tuesday, June 30, 2026

ServiceNow: Steps of Scheduled Email for an existing report not capturing in local updateset

ServiceNow Steps of Scheduled Email for an existing report not capturing in local updateset

Create a Scheduled Email of an existing report, push your update set to another environment, and the scheduled report simply isn't there. This isn't a bug, and it isn't something that's changed across ServiceNow versions — it's deliberate platform behavior, and it's still true on current releases. Community threads reporting this exact issue go back to 2019 and as recently as late 2024, which tells you it's architectural, not a defect waiting to be patched.

Why This Happens

Whether a table's changes get captured in an update set at all comes down to a single dictionary attribute: update_synch. A table needs update_synch=true set on its dictionary definition for the platform to track changes to its records as update set entries. Tables that don't have this attribute — sysauto_report (Scheduled Reports) among them — simply aren't watched by the update set mechanism, no matter what you change on them.

This is intentional, not an oversight. Update Sets are built to move configuration — business rules, client scripts, UI policies, workflow definitions — between environments. Scheduled Reports, Scheduled Jobs, and similar records sit closer to data in ServiceNow's own mental model: they reference specific recipients, specific report instances, specific runtime schedules. The platform's default position is that this kind of record shouldn't silently ride along in a configuration migration.

You can check whether any given table is captured by going to System Definition > Dictionary, finding that table's base record (the one with an empty Column name), and checking its Attributes field for update_synch=true.

The Better Fix: Force the Record Into Your Update Set

Rather than exporting and importing XML by hand, you can add a specific record to your current update set directly, using GlideUpdateManager2:

var gr = new GlideRecord('sysauto_report');
gr.addQuery('sys_id', 'your_scheduled_report_sys_id');
gr.query();
if (gr.next()) {
    var um = new GlideUpdateManager2();
    um.saveRecord(gr);
    gs.print('Record added to current update set');
}

Run this from System Definition > Scripts - Background, with the update set you actually want it in selected as your current update set first. This has real advantages over the manual XML approach:

  • The record moves through your normal update set promotion process — no separate file to track, remember, or lose.
  • The destination environment doesn't need elevated security_admin privileges to receive it, since it's coming in as a standard update set entry rather than a raw XML import.

One limitation to know: GlideUpdateManager2 doesn't work from a scoped application — this needs to run in the Global scope.

The Fallback: Manual XML Export/Import

If you'd rather not run a background script — or you're dealing with a one-off promotion — the manual approach still works exactly as it always has:

Exporting from the source environment:

  1. Open the Scheduled Email of Report record.
  2. Right-click the list header and select Export > XML (This Record).
  3. Save the XML document locally.

Importing into the destination environment:

Because this is a direct XML import rather than a normal update set, the destination environment does require elevated privileges:

  1. Click the elevated privileges (lock) icon beside your username, check security_admin in the Activate an Elevated Privilege dialog, and click OK.
  2. Navigate to Reports > Scheduled Reports.
  3. Right-click the list header and select Import XML.
  4. Browse to the XML file and click Upload.

It's Not Just Scheduled Reports

The original version of this article guessed that Scheduled Jobs would have the same problem — that guess was correct, and it's worth being explicit about why, plus a few other categories that catch people off guard the same way:

  • Scheduled Jobs (sysauto, sysauto_script) — same root cause, same fix. Use GlideUpdateManager2().saveRecord(gr) against the relevant table, or export/import XML the same way.
  • Users, Roles, Groups, and group membership — not captured, by design; these are managed independently of configuration promotion.
  • Transactional data — Incidents, Problems, Changes, and similar records are never meant to travel via update set at all. If you need to move this kind of data between environments, that's what Import Sets and Transform Maps are for, not Update Sets.
  • Homepages and personal dashboard content — generally not captured either, since these are largely treated as per-user data rather than shared configuration.

If you find yourself needing to move several of these regularly, ServiceNow Share has an "Add to Update Set" utility that generalizes the GlideUpdateManager2 technique above into a reusable tool, rather than writing a one-off background script every time.

The Takeaway

If a change doesn't show up in your update set, the first thing to check isn't whether something's broken — it's whether that table has update_synch=true at all. If it doesn't, that's expected behavior, and GlideUpdateManager2().saveRecord() is generally the cleaner way to move that specific record than a manual XML round-trip.

Sunday, May 31, 2026

ServiceNow: Creating a Global List Report (and Why Sharing Isn't Just a Checkbox)

ServiceNow Creating a Global List Report

To create a Global Report of List type in ServiceNow, follow these steps:

  1. Enter Report in the filter navigator.
  2. Click Reports > View / Run. This opens the Reports screen.
  3. Click New to start a report.
  4. Populate the following fields.

Report Configuration Fields

  • Name: Name for the report.
  • Type: Select List.
  • Table: Select the table the report pulls from — for example, Hardware (alm_hardware).
  • Group By: Leave blank if grouping isn't needed.
  • Export details: Keep this checked if you want export options available on the report output.
  • Header Footer Template: Default, unless your organization has a custom template configured for exports like PDF.
  • Filter and Order: Sets which records from the selected table appear in the report, and in what order.
  • Columns: Move the desired fields from Available to Selected. For reference fields — shown with a green plus-sign icon — selecting the field and clicking the + icon expands it, letting you drill into fields on the referenced record rather than just the reference field itself.

Once everything is configured, click Run Report to preview the output in the grid below, then Save to save the report.

Note on the interface: on current versions, this same configuration is often presented through Report Builder, a more visual, drag-and-drop report creation experience rather than the classic field-by-field form described above. The underlying concepts — table, columns, filters, grouping — are the same either way; only the screen layout differs depending on your instance's version and configuration.

Sharing the Report — A Separate Step, and Role-Gated

This is where the original version of this guide fell short, and it's worth being explicit about: making a report "Global" is generally a separate step from building it, done through Sharing rather than a field on the creation form itself.

  1. Open the saved report.
  2. Click the Sharing icon (or, on some versions, select Sharing from the dropdown next to Save).
  3. In the Sharing settings, set Visible to:
  4. Me — only you can see it.
  5. Groups and Users — visible to specific groups or a custom list of users.
  6. Everyone — visible instance-wide, which is what actually makes a report "Global."
  7. Click OK.

The part that trips people up: you need one of a specific set of roles for the Sharing option to even appear, let alone work as expected:

  • report_group — required for the Groups and Users option to be available at all. Without it, that option simply doesn't show up in the dialog.
  • report_global — required to set a report's visibility to Everyone.
  • report_admin — full administrative rights over reports generally, regardless of who created them.

If a user only has basic reporting access (report_user) without any of the above, they won't see a Sharing option on the report at all — which is a common source of "why can't I share this report" confusion that has nothing to do with the report configuration itself.

One more practical note: sharing only controls report visibility, not underlying data access. If the people you've shared a report with don't have access to the records it's built on (via ACLs), sharing the report won't bypass that — they'll see the report shell without the data it's supposed to show.

For bulk sharing changes across many existing reports — say, moving 50 reports from role-based sharing to a specific group — this is scriptable directly against the sys_report table, since sharing type and target are stored as fields on the report record itself rather than requiring the UI to be used one report at a time.

Friday, March 06, 2026

ServiceNow: Remove Role from Large User Group Without Timeout (20k+ Users)

ServiceNow - Remove Role from Large User Group Without Timeout

Managing roles in large ServiceNow environments can create performance challenges that don't show up until you're dealing with a genuinely large group. One common trigger: removing a role from a group containing thousands of users.

I recently ran into this with a group of more than 20,000 users that had an incorrect role assigned. Removing the role through the UI consistently timed out. This article covers why that happens and how to remove it safely.

The Problem

A role was mistakenly assigned to a group with more than 20,000 users. The role also had several child roles, which multiplied the number of permission recalculations needed across the platform.

Attempting to remove the role through the UI, or through a synchronous Fix Script, consistently resulted in timeout errors. The core issue: removing the role triggers role recalculation for every user in the group, all within the same request.

Why the Timeout Happens

When a role is removed from a group, ServiceNow re-evaluates role inheritance for every member of that group. The inheritance chain looks roughly like this:

User
   ↓
User Group
   ↓
Group Role (sys_group_has_role)
   ↓
Inherited Roles
   ↓
User Role Updates

With tens of thousands of users, that recalculation — done synchronously, inside a single UI transaction — can easily exceed the platform's request execution limits and time out before it finishes.

The Fix: Asynchronous Group Role Updates

ServiceNow has a system property that moves group role updates to a background job instead of processing them inside the UI request:

glide.ui.schedule_slushbucket_save_for_group_roles = true

Check this before assuming you need to set it — on most current instances, this property now ships enabled by default rather than needing to be turned on manually. Search sys_properties.list for it and confirm its current value before changing anything.

When it's enabled, adding or removing roles on a group is handed off to a scheduled background job rather than processed in your session. That's what avoids the timeout — but it also means the change isn't instant. You'll typically see an informational banner at the top of the group form, and you'll need to refresh to confirm the update actually completed.

A few things worth knowing before you rely on it:

  • It doesn't apply to changing a group's Parent field. If your timeout is happening on a parent-group change rather than a role change, this property won't help — that's a separate, documented limitation.
  • It can interact awkwardly with certain HR-scoped roles. Some administrators have hit cases where adding a user with an HR role to a group silently fails while this property is enabled, requiring a temporary toggle off, then back on, to complete the change. If a role addition on an HR-related group doesn't seem to be taking effect, this is worth checking.
  • It can obscure the "Changed by" field on role-related audit trails, since the update is performed by a background job rather than attributed directly to your session. If accurate attribution matters for compliance, keep this in mind.

Optional Fix Script for Role Removal

If you need to automate the removal rather than do it through the UI, you can delete the relationship record directly from sys_group_has_role:

var groupName = 'Your_Group_Name';
var roleName = 'role_a';

var group = new GlideRecord('sys_user_group');
group.addQuery('name', groupName);
group.query();

if (group.next()) {

    var role = new GlideRecord('sys_user_role');
    role.addQuery('name', roleName);
    role.query();

    if (role.next()) {

        var groupRole = new GlideRecord('sys_group_has_role');
        groupRole.addQuery('group', group.sys_id);
        groupRole.addQuery('role', role.sys_id);
        groupRole.query();

        while (groupRole.next()) {
            groupRole.deleteRecord();
            gs.info('Removed role ' + roleName + ' from group ' + groupName);
        }

    } else {
        gs.info('Role not found: ' + roleName);
    }

} else {
    gs.info('Group not found: ' + groupName);
}

This removes the group-role relationship directly, which is what actually drives the downstream recalculation — same effect as removing it through the UI, just scriptable. With the async property enabled, the recalculation this triggers still runs as a background job rather than inline with the script.

What Happens After Removing the Role

Once the group-role relationship is removed, ServiceNow recalculates role inheritance for affected users in the background (assuming the async property is enabled). If a user doesn't inherit that role through any other group or direct assignment, it's removed from their user record once the recalculation completes.

Tracking Who Changed What

If you're doing access cleanup like this in an environment where auditability matters, it's worth knowing about glide.role_management.v2.audit_roles. When enabled, it logs role changes to the sys_audit_role table — useful for showing exactly what changed and when during a cleanup like this. It isn't available out of the box; you'd need to create the property and set it to true if you want this tracking.

Best Practices for Large Role Changes

  • Check whether glide.ui.schedule_slushbucket_save_for_group_roles is already enabled before assuming you need to turn it on.
  • Test role changes in a lower environment first, especially for groups with HR-scoped roles given the known interaction above.
  • Monitor the background job queue when performing changes on large groups — don't assume completion just because the UI stopped showing a spinner.
  • Avoid large role changes during peak platform usage, since background jobs still compete for system resources.
  • If attribution matters for compliance, consider enabling role change auditing before making the change, not after.

Conclusion

Removing roles from large groups can time out if ServiceNow tries to process every user's role recalculation within a single request. Enabling asynchronous group role updates — checking first whether it's already on — moves that work to a background job and avoids the timeout, though it's worth knowing its edge cases around parent-field changes, HR-scoped roles, and audit attribution before relying on it for a sensitive cleanup.

Sunday, December 14, 2025

Service Catalogue Fulfilment Processes Explained: Flow vs. Workflow vs. Execution Plan

Service Catalogue Fulfilment Processes Quiz Explained

Understanding how ServiceNow fulfils service catalogue requests is foundational knowledge for administrators and certification candidates. This question focuses on identifying the available fulfilment process options and clarifies what is — and isn't — used in real implementations.

The quiz question

What options are available to define the fulfilment process for a service catalogue item?
Select 3 answers from the options below.

Correct answers

1. Flow
2. Workflow
3. Execution Plan

Incorrect options

Plan
Roadmap

Detailed explanation

When a user orders a catalogue item, ServiceNow creates a request that follows a predefined fulfilment process. This process controls how approvals are handled, how tasks are created and assigned, and how the request is completed. ServiceNow's own Service Catalog API documentation confirms it directly: a catalog item must reference a flow, workflow, or execution plan that defines how the item request is fulfilled — exactly three supported mechanisms, nothing more.

✔️ 1. Flow

Flows are created using Flow Designer and represent the modern, recommended approach. They provide no-code/low-code automation, handle approvals, tasks, notifications, and conditions, and are generally easier to read, maintain, and extend than the alternatives. Under the hood, a flow is stored as a record on the sys_hub_flow table.

Best suited for: most new implementations and future-proof designs — ServiceNow's own documentation explicitly recommends flows as the fulfilment method for new catalog items.

✔️ 2. Workflow

Workflows are the legacy automation method for fulfilment, built in the classic Workflow Editor rather than Flow Designer. They support complex logic and branching paths, and can stop or continue based on approvals or conditions. Workflows are stored on the wf_workflow table, and are still widely used in existing implementations that predate Flow Designer's maturity.

Note: while still supported, workflows are gradually being replaced by flows — ServiceNow's guidance is to use the flow property for new implementations rather than building new workflows.

✔️ 3. Execution Plan

Execution plans define simple, linear fulfilment processes. They describe how an item is procured, configured, or installed; consist of one or more predefined tasks; and involve no branching or complex logic. They're stored on the sc_cat_item_delivery_plan table. Compared to workflows, execution plans are strictly for task generation and sequencing — they can't be designed with a graphical editor, and the requester sees each task listed as a discrete stage rather than a smoother workflow-style progression.

Ideal for: straightforward, task-based fulfilment scenarios — and for cases where you need to build the process programmatically or through imports rather than a visual designer.

A detail worth knowing: a catalog item can technically have a flow, a workflow, and an execution plan all configured at once. When that happens, ServiceNow doesn't run all three — the flow takes precedence. If you inherit a catalog item that seems to be ignoring its execution plan or workflow, check whether a flow is also attached; that's almost always why.

Why the other options are incorrect

🚫 Plan

Not a valid fulfilment mechanism for catalogue items. It's too generic and isn't a recognized ServiceNow fulfilment feature — a plausible-sounding distractor, but not something you'll find on the catalog item form.

🚫 Roadmap

Roadmaps are typically used for strategic or planning purposes (think Now Value or Strategic Portfolio Management), and have no role in request fulfilment automation.

Overall explanation summary

When preparing to fulfil catalogue item requests, administrators typically:

  1. Set up fulfilment groups to assign request tasks
  2. Define fulfilment processes using Flow Designer flows, workflows, or execution plans
  3. Assign the fulfilment process to catalogue items

Each fulfilment method serves a different use case, but all three are valid and supported — the right choice comes down to complexity, maintainability, and how future-proof the implementation needs to be.

Fulfilment process comparison

Feature / Aspect Flow Workflow Execution Plan
Underlying tablesys_hub_flowwf_workflowsc_cat_item_delivery_plan
Process typeVisual, modern automationLegacy automationLinear task sequence
Complexity supportMedium to highHighLow
Branching logicYesYesNo
ApprovalsYesYesNo
Task assignmentYesYesYes
MaintenanceEasyModerateVery easy
Best use caseMost catalogue itemsExisting complex setupsSimple fulfilment
Precedence if multiple are setAlways winsOverridden by flowOverridden by flow

Quick exam tip

Remember for exams:
✔ Fulfilment processes = Flow + Workflow + Execution Plan
✘ Ignore generic distractors like Plan or Roadmap
✔ If more than one is configured on the same item, Flow wins

One-line memory aid

Catalogue fulfilment follows either a modern flow, a legacy workflow, or a simple execution plan — and if more than one is attached to the same item, the flow always wins.

Additional learning resource

Final thoughts

This question reinforces a key ServiceNow concept: multiple fulfilment mechanisms exist, and choosing the right one depends on complexity, maintainability, and future readiness. For exam preparation, remember Flow, Workflow, and Execution Plan — and ignore generic-sounding distractors like Plan or Roadmap.


This article reflects ServiceNow's Service Catalog API documentation, including the flow-takes-precedence rule when multiple fulfilment mechanisms are configured on the same catalog item. Table names and precedence behavior are consistent across recent release families as of this writing — verify against your own instance if you're on an older release.

ServiceNow Admin Role and Elevated Privileges Explained: A CSA Exam Deep Dive

ServiceNow Admin Role and Elevated Privileges Explained

ServiceNow role management is a critical topic that shows up constantly in certification exams — and it's trickier than it looks, because the rules around the admin role aren't just "roles grant permissions." There's a whole separate layer underneath called elevated privilege roles that governs who can grant what to whom.

In this article, we'll start from a real exam-style quiz question about the admin role, walk through why each option is right or wrong, and then zoom out to cover the full elevated privilege model — including how it applies beyond just security_admin, and what it means for building your own high-security roles.

The quiz question

Which of the following is a true statement about the admin role?
Select 3 answers from the options below.

Correct answers

1. Non-admin users cannot add users to a group containing the admin role.
2. To grant the admin role to a user, the granting user must also have the admin role.
3. A user with only the admin role cannot grant the security_admin role to other users.

Incorrect / commonly misunderstood options

A user with only the user_admin role can grant the admin role to other users.
A non-admin user with only the security_admin role can add a user to a group that contains the security_admin role.

Detailed explanation

Let's walk through each statement and understand why it's correct or incorrect.

✔️ 1. Non-admin users cannot add users to a group containing the admin role

This statement is true. The admin role is highly privileged, and only users who already have the admin role can manage group membership for groups that contain it. This restriction directly prevents privilege escalation — without it, a user_admin could simply add themselves to an admin-carrying group instead of being granted the role directly.

Key takeaway: admin access is tightly controlled and cannot be indirectly granted via group management by non-admin users.

✔️ 2. To grant the admin role to a user, the granting user must also have the admin role

This statement is true. ServiceNow's documentation on elevated privilege roles states this explicitly: to grant the admin role to a user, the granting user must also have the admin role — a user with only the user_admin role cannot grant it, no matter how much user-management access they otherwise have.

Exam tip: don't confuse "can manage users" with "can grant any role." user_admin covers the former; the admin role's own grant is a special case carved out on top of that.

✔️ 3. A user with only the admin role cannot grant the security_admin role to other users

This statement is true, and it's the one that trips up the most exam-takers. security_admin is an elevated privilege role — the only one shipped in the base system. To grant it to someone else, the granting user must have the admin role and must first elevate their own session to security_admin before they can hand it out. Simply holding the admin role isn't enough on its own.

Why this matters: security_admin controls access to Access Control Lists (ACLs) and High Security Settings — the layer that decides who can read, write, or delete records on protected tables. ServiceNow deliberately adds friction here so that a compromised or careless admin session can't silently rewrite security rules.

❌ 4. A user with only the user_admin role can grant the admin role to other users

This statement is false. The user_admin role allows management of users and groups generally, but it does not allow granting the admin role specifically. Granting admin access always requires the admin role itself.

Common pitfall: assuming user_admin is powerful enough to grant every role just because it can touch the user and group forms.

❌ 5. A non-admin user with only the security_admin role can add a user to a group that contains the security_admin role

This statement is false. Group management for privileged roles still requires admin access — holding security_admin alone doesn't bypass that. And security_admin itself is session-based: it must be actively elevated, and it disappears again at logout or session timeout, so it was never meant to function as a standing, always-on privilege in the first place.

Important note: security roles are controlled more strictly than standard administrative roles, precisely because they gate the controls that everything else depends on.

Why elevated privilege roles exist at all

Users with the admin role can typically modify any record on any table. That's necessary for day-to-day administration, but it also means an admin session — potentially compromised, potentially just a careless click — could rewrite the very ACLs that control table security. Elevated privilege roles exist to put a manual speed bump in front of exactly that class of change.

Practically, that means:

  • Elevated roles are not active by default, even for a user who technically holds them — they have to be manually elevated during the session, via User menu → Elevate Roles.
  • Elevation is session-based: it lasts only for the current login session and is cleared on logout, session timeout, or manual de-elevation.
  • If an elevated role contains another elevated role, holding one does not automatically elevate the other — each has to be elevated separately.
  • Instance administrators can set a system property to force admins to always manually select their elevated role rather than defaulting to it.

Elevated privilege isn't just for security_admin

A detail a lot of exam guides skip: security_admin is the only role that ships as elevated privilege out of the box — but it isn't a special, hardcoded exception. Elevated privilege is a configurable attribute on the role record itself, which means administrators can mark any custom role as elevated privilege too.

On the Role form, the relevant fields are:

  • elevated_privilege — when true, a user must manually accept the role each session before its permissions become active. Defaults to false.
  • grantable — whether the role can be granted independently, versus only being available bundled inside another role that contains it. Defaults to true.

This matters for GRC/IRM and platform architecture work specifically: if you're designing a role that governs something sensitive — say, control over integration credentials, or access to a compliance-sensitive table — flagging it as elevated privilege gives you the same "must actively opt in this session" protection that ServiceNow applies to security_admin, without needing to touch platform-level security code.

Role hierarchy at a glance

Role Can grant admin? Can grant security_admin? Requires elevation to use? Can manage admin-carrying groups?
user_adminNoNoNoNo
admin (not elevated)YesNoNoYes
admin, elevated to security_adminYesYesYes (session-based)Yes

Common exam pitfalls on this topic

  • Treating "has the admin role" and "is currently elevated" as the same thing — they're not. An admin who hasn't elevated to security_admin this session functionally cannot touch ACLs or grant security_admin, even though their role assignment hasn't changed.
  • Assuming user_admin is a subset of admin with slightly fewer permissions — it isn't a scaled-down admin, it's a separate role with a specific, bounded scope (user and group management) that explicitly excludes granting admin or admin-group membership.
  • Forgetting that elevation is per-role. If a custom role bundles security_admin inside it, elevating to the custom role does not automatically elevate security_admin — each elevated role inside it must be elevated on its own.
  • Assuming security_admin is a permanent role assignment like most others. It's designed to be requested, used, and dropped within a session, not left "on" indefinitely.

Overall summary

Here's a consolidated view of the rules tested in this question:

  • Non-admin users cannot manage admin group membership.
  • The user_admin role cannot grant the admin role.
  • To grant admin, you must already be admin.
  • The admin role alone cannot grant security_admin.
  • To grant security_admin, a user must have the admin role and elevate to security_admin before assigning it.

The elevation step is mandatory and time-bound, reinforcing ServiceNow's defense-in-depth approach to security administration.

Final thoughts

Questions like this test more than memorization — they test whether you understand ServiceNow's security and role hierarchy as a layered system, not a flat list of permissions. If you're preparing for CSA, CAD, or other ServiceNow certifications, the elevated privilege model is worth understanding beyond just security_admin: it's the same mechanism you'll reach for if you ever need to design your own high-security custom role.

Happy learning 🚀


This article reflects ServiceNow's documented elevated privilege role model, including the elevated_privilege and grantable role attributes. Exact menu labels (e.g. "Elevate Role" vs. "Elevate Roles") can vary slightly by release — verify against your own instance's User menu.

Why ServiceNow Schedule Calendars Suddenly Stop Working (Even Without Role Changes)

Why ServiceNow Schedule Calendars Suddenly Stop Working (Even Without Role Changes)

A user reports:

"Last month I could open the Schedule Calendar using 'Show Schedule,' but now I get a Security constraints prevent access message."

No role changes. No group changes. No recent deployments touching On-Call. Yet the calendar suddenly becomes inaccessible.

This scenario is far more common than it appears, and it usually isn't a defect. It's a data-level permission shift — a silent change that occurs underneath the roles and groups. Let's break it down.

1. Schedule access isn't controlled only by roles

Many ServiceNow users assume:

"If I'm in the right group and have on-call roles, I can access the schedule."

But schedule access depends on ownership and underlying ACLs, especially on these tables:

  • cmn_schedule — the base schedule record
  • cmn_rota — the on-call shift record layered on top of a schedule
  • cmn_schedule_span and, for On-Call Scheduling specifically, roster_schedule_span — the individual time spans that make up the calendar view

If the owner group, schedule, or rota visibility shifts — even slightly — a user may lose access without any admin touching their roles.

Typical causes

  • Schedule ownership changed to a group the user is no longer part of
  • Rota owner field updated accidentally
  • A new ACL was introduced by another team or plugin
  • A schedule was copied from another environment with different permissions

2. "Show Schedule" loads a calendar UI page — and that page enforces ACLs

The "Show Schedule" link loads a specific UI Page that visually renders the calendar. This page queries schedule records, loads rota and span data, and renders only what the user is allowed to see.

If the user fails even one ACL check on any related record (for example, a span they cannot read), the entire page can fail with:

Security constraints prevent access to requested page

Even though the user has the same roles and the same group membership, they can still fail an ACL evaluation because the data they're trying to view is now restricted.

3. Why it "used to work" and now it doesn't

This is the most confusing part for users. It happens because someone changed the schedule's group, the rota's owner, a span record's permissions, or a schedule was overwritten or reimported — or a Dev → Test → Prod migration created mismatched access.

These changes often happen silently:

  • A rota owner edits the group
  • Another support team updates a schedule
  • Copy changes from one environment alter ownership
  • A plugin update modifies ACL inheritance

No code change. No role change. But access breaks.

4. The quickest way to diagnose the issue (admin steps)

Step 1 — Test as the impacted user (Impersonate). Try to open the group, the on-call schedule, the specific rota, and the calendar UI page. Find what fails.

Step 2 — Check these ACLs. Review read ACLs on cmn_schedule, cmn_rota, and cmn_schedule_span (or roster_schedule_span if On-Call Scheduling is active). If any "read" ACL denies access, the calendar collapses completely.

Step 3 — Confirm schedule ownership. Check Schedule → Group, Rota → Group, and Coverage/Span → Owned by which group. If ownership belongs to a private group the user cannot see, the calendar stops loading.

5. How to prevent this issue in the future

  • Lock schedule ownership. Assign a single designated owner group for on-call schedules and restrict edit access.
  • Prevent accidental schedule overwrites. If teams import or export schedules across environments, enforce update sets with fixed ownership and restrict access to schedule tables.
  • Build a diagnostic report that flags schedules owned by private groups, rota records with mismatched permissions, and spans that belong to inconsistent groups.
  • Add a knowledge article for end users so that instead of panic escalations, they understand what the error means, why it occurs, and how to request access properly.

Conclusion

When "Show Schedule" suddenly stops working, it's rarely a defect — it's usually data-level permission drift. The underlying tables powering on-call scheduling are sensitive to ownership and group visibility, and even a small shift can break the UI page.

With controlled ownership, regular audits, and a simple access troubleshooting checklist, this becomes a preventable issue.


Table and field names referenced here reflect the base Common Schedule and On-Call Scheduling data model. Exact ACL configuration and inherited access rules can vary by instance, active plugins, and customizations — verify against your own instance before making ACL changes.

Sunday, December 07, 2025

ServiceNow CSRF Token Errors in Integrations: Root Causes and Fixes (Updated)

Understanding ServiceNow CSRF Token Errors in Integrations

CSRF protection in ServiceNow is designed to guard browser-based UI sessions, not machine-to-machine API traffic. So when an external tool such as AWS Glue receives "Invalid CSRF token" or "Your session has expired", the message is misleading. It almost never means CSRF protection is genuinely blocking the call — it usually means the authentication flow itself failed and ServiceNow silently redirected the request to a login page.

What makes this confusing is that the same integration often works fine against one instance and fails in another, which sends both teams chasing the wrong root cause.

This article explains why that happens and how to diagnose and fix it on current ServiceNow releases.

What actually causes "CSRF" errors in integrations

A ServiceNow CSRF-style error on an integration call almost always comes down to one of two things.

1. ServiceNow treats the request as a browser session instead of an API call. If the request hits a UI-oriented endpoint, or is missing headers that mark it as API traffic, ServiceNow applies session/CSRF validation rules meant for the browser.

2. The authentication flow fails and redirects. When OAuth token exchange fails, ServiceNow can redirect to a login page instead of returning a JSON error. The external system receives an HTML login page where it expected a token or API response, and that gets surfaced upstream as a session/CSRF error.

A properly authenticated, correctly scoped API call should never trigger a CSRF error. If you're seeing one, treat it as a symptom of an authentication or routing problem, not an actual CSRF violation.

Why AWS Glue (or similar tools) might trigger this

AWS Glue integrates with ServiceNow by performing OAuth authentication, then REST API reads/writes against /api/now/table/ endpoints. When that sequence breaks down, Glue typically surfaces one of the two messages above. Either one means ServiceNow did not accept the incoming credentials as valid API traffic and fell back to browser-session handling. The real causes are almost always one of the following.

1. Wrong or deprecated OAuth grant type

This is the most common root cause, and it has shifted in the last couple of release cycles. The current recommendation is to use the Client Credentials grant (client ID + client secret only, no end-user credentials) for machine-to-machine integrations like Glue. This is what ServiceNow documents as the correct pattern for service-to-service API access.

A note on ROPC: Resource Owner Password Credentials — the grant type that also requires a username and password — still exists on the platform, but it's now explicitly discouraged. It's deprecated under the OAuth 2.1 specification, and ServiceNow added a system property, glide.oauth.inbound.ropc.grant_type.disabled, that instance admins can (and increasingly do) set to true to block it outright.

If your instance has that property enabled and Glue (or its OAuth app registration) is still configured for ROPC, every token request will fail, ServiceNow will redirect toward a login page, and Glue will report it as a CSRF/session error — even though the actual cause is a disabled grant type. Check the OAuth Transaction Log for a disabled_grant_type error specifically; it's a fast way to confirm this cause.

2. OAuth client ID mismatch across environments

Each ServiceNow instance (dev, test, prod) has its own OAuth Application Registry entry and therefore its own client ID and secret, even for "the same" integration. A common failure pattern:

  • Correct client ID configured for DEV
  • Correct client ID configured for PROD
  • Stale or incorrect client ID left over in TEST

Authentication fails silently against the mismatched environment, ServiceNow falls back to the login URL, and the resulting error looks like a CSRF failure rather than what it is — a credentials mismatch.

3. Identity provider "External Logout Redirect" misconfiguration

If your instance uses an external identity provider, check the External Logout Redirect setting. When OAuth authentication fails, some configurations redirect to this URL instead of returning a proper error response. Glue then receives an HTML "session expired" page instead of JSON, and that gets interpreted downstream as a CSRF failure. The fix is usually to correct the redirect target, not to touch CSRF settings at all.

4. The integration user account is locked, inactive, or has an expired password

If the integration relies on a specific ServiceNow user account (common with ROPC, but also relevant if a service account is tied to token issuance), that account has to be active, unlocked, and — if ROPC is somehow still in play — have a valid, non-expired password. If the account is locked in one environment but not another, you'll see the integration work everywhere except that one instance, which is exactly the confusing pattern this article opened with.

5. Instance-specific redirect or SSO policy differences

One instance may simply have stricter security posture than another — a tighter SSO policy, more restrictive login rules, or IP allowlisting that the integration's egress IPs don't match. Any of these can cause OAuth to fail in one environment while working fine in another with an otherwise identical configuration.

6. The API endpoint is being treated as a UI page

If the integration is pointed at a UI-facing URL instead of a proper REST endpoint under /api/now/ — even something as small as a missing /now segment — ServiceNow applies browser session rules and enforces CSRF validation. Double-check the full endpoint path, not just the base instance URL.

7. OAuth scope mismatch

If the OAuth Application Registry on the target instance defines a specific set of scopes and Glue's OAuth client is configured to request a scope that isn't registered there, the token request is rejected and ServiceNow redirects to login — again surfacing as "session expired." This is worth checking specifically when an integration works in one instance and not another with a similarly named but differently scoped OAuth registration.

How to diagnose this systematically

Step 1 — Check the OAuth Transaction Logs. Navigate to System OAuth > Application Registry, open the relevant entry, and review its OAuth Transaction Logs. Failed transactions will show the actual cause directly: wrong or disabled grant type, invalid client ID, unexpected redirect, or a specific authentication error code.

Step 2 — Verify the integration user, if a user-based flow is involved. Check that the account is active, not locked, and — if a password-based flow is somehow still configured — that the password hasn't expired.

Step 3 — Compare the OAuth Application Registry across instances. Check these fields side by side between the working and failing instance:

  • OAuth application name
  • Client ID
  • Client Secret
  • Token URL
  • Redirect URL
  • Grant type(s) enabled
  • Scopes
  • Whether glide.oauth.inbound.ropc.grant_type.disabled is set differently between instances

When an integration works in one instance and fails in another, at least one of these fields is the difference.

Step 4 — Get logs from the external tool. Ask the Glue (or equivalent) team for their request/response logs. You're looking for whether the token endpoint returned JSON or an HTML login page, what the actual redirect URL was, and the raw HTTP status code. If they got a login page instead of a token or API response, the OAuth flow — not CSRF — is the problem.

Step 5 — Confirm the correct endpoints are being called. The token request should go to:

https://<instance>.service-now.com/oauth_token.do

and API calls should be scoped under:

/api/now/table/

Anything else gets treated under browser/UI rules, which is where CSRF enforcement kicks in.

Final thoughts

CSRF-labeled errors in ServiceNow integrations are almost always a downstream symptom of an OAuth authentication or configuration issue — not an actual CSRF violation. On current releases, that most often traces back to a deprecated or disabled ROPC grant type, since ServiceNow has been actively pushing instances toward Client Credentials for machine-to-machine integrations.

Work through grant type, client ID/secret accuracy, scopes, redirect configuration, integration user status, and endpoint URLs in that order, and you'll typically isolate the real cause — and get the integration back online — within minutes rather than hours.


This article reflects current ServiceNow guidance on OAuth 2.0 authentication for inbound integrations, including the ongoing deprecation of the Resource Owner Password Credentials grant type. Exact system property names and default behavior can vary by release family — verify against your instance's OAuth Transaction Logs and System Properties before making changes.