Skip to main content

Scenario: ServiceNow to Azure Identity Ticket Routing

Overview

This scenario describes an outbound integration from ServiceNow to Azure Entra ID, where ServiceNow looks up user information from Microsoft Graph to route tickets based on organizational data.

Direction: ServiceNow → Azure (opposite of Scenario 01)


The Setup — What Was Built and Why

Company: Contoso Corp Date: June 2025

The IT Service Desk wants to automatically route identity-related tickets (password resets, access requests, account issues) based on the user's department, manager, and location — data that lives in Azure Entra ID, not ServiceNow.

An integration engineer builds a Business Rule that calls Azure Graph API to look up users.


Integration Flow Diagram

┌─────────────────────────────────────────────────────────────────────────────┐
│ SERVICENOW INSTANCE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. BUSINESS RULE: "Auto-route identity tickets via Entra" │
│ ├── Table: incident │
│ ├── When: after insert │
│ ├── Condition: category = 'Identity' OR category = 'Access Request' │
│ └── Action: Calls Script Include "AzureGraphRouter" │
│ │
│ ↓ │
│ │
│ 2. SCRIPT INCLUDE: "AzureGraphRouter" │
│ ├── Created by: mike.johnson@contoso.com │
│ ├── Last modified: 2025-06-15 │
│ └── Logic: │
│ - Extract caller's email from incident │
│ - Call REST Message to look up user in Entra │
│ - Parse department, manager, location from response │
│ - Route ticket to appropriate fulfillment group │
│ │
│ ↓ │
│ │
│ 3. OUTBOUND REST MESSAGE: "Azure Graph API" │
│ ├── Name: "Graph - sn-ticket-router" │
│ ├── Endpoint: https://graph.microsoft.com │
│ └── HTTP Methods: │
│ ├── GetUserByUPN: GET /v1.0/users/{upn} │
│ ├── GetManager: GET /v1.0/users/{id}/manager │
│ └── GetDirectReports: GET /v1.0/users/{id}/directReports │
│ │
│ ↓ │
│ │
│ 4. OAUTH ENTITY PROFILE: "Microsoft Graph OAuth" │
│ ├── OAuth Application: "sn-ticket-router-oauth" │
│ ├── Client ID: b085873d-e521-4e2d-9ae6-92554800c8de │
│ ├── Client Secret: [stored in ServiceNow] │
│ └── Grant Type: client_credentials │
│ │
│ ↓ │
│ │
│ 5. OAUTH PROVIDER: "Microsoft identity platform" │
│ ├── Token URL: https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
│ ├── Scope: https://graph.microsoft.com/.default │
│ └── Auth flow: OAuth 2.0 Client Credentials │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

│ HTTPS + OAuth Token

┌─────────────────────────────────────────────────────────────────────────────┐
│ AZURE ENTRA ID │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 6. APP REGISTRATION: "sn-ticket-router" │
│ ├── Application ID: b085873d-e521-4e2d-9ae6-92554800c8de │
│ ├── Created: 2025-06-10 │
│ ├── Owner: mike.johnson@contoso.com │
│ └── Client Secret: expires 2026-12-10 │
│ │
│ 7. SERVICE PRINCIPAL (Enterprise App) │
│ ├── Object ID: 7a8b9c0d-... │
│ ├── Sign-in logs: ~200 calls/day │
│ └── Last sign-in: 2 minutes ago │
│ │
│ 8. API PERMISSIONS (Microsoft Graph) │
│ ├── User.Read.All (Application) — Read all users' profiles │
│ ├── Directory.Read.All (Application) — Read directory data │
│ └── [Optional] AuditLog.Read.All — Read audit logs │
│ │
│ 9. MICROSOFT GRAPH API │
│ └── Returns: displayName, department, jobTitle, manager, │
│ officeLocation, userPrincipalName, etc. │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

Data Flow Example

  1. User creates ticket: "I need access to the Finance SharePoint site"
  2. Business Rule fires: Category is "Access Request"
  3. Script calls Graph API: GET /v1.0/users/jane.doe@contoso.com
  4. Graph returns:
    {
    "displayName": "Jane Doe",
    "department": "Finance",
    "jobTitle": "Senior Accountant",
    "manager": { "displayName": "Bob Smith" },
    "officeLocation": "Seattle"
    }
  5. Script routes ticket: Finance users → "IT-Finance-Provisioning" group

Why This Matters for SecurityV0

Cross-Service Identity Chain

ServiceNow Business Rule
└── owned by: mike.johnson (ServiceNow user)

ServiceNow Script Include "AzureGraphRouter"
└── created by: mike.johnson
└── calls: REST Message

ServiceNow OAuth Entity "sn-ticket-router-oauth"
└── client_id: b085873d-e521-4e2d-9ae6-92554800c8de
└── links to: Azure App Registration

Azure App Registration "sn-ticket-router"
└── app_id: b085873d-e521-4e2d-9ae6-92554800c8de
└── owner: mike.johnson@contoso.com
└── permissions: User.Read.All, Directory.Read.All

What Can Go Wrong

MonthEventRisk
1-3Working as designedNone
6Mike leaves companyOrphaned on both sides
8Someone adds User.ReadWrite.All to fix a bugScope drift
10ServiceNow upgrade breaks auth, admin regenerates secretNo owner to approve
12Client secret expiresIntegration breaks, no one to fix

Blast Radius

If this integration is compromised (ServiceNow Script Include vulnerability, stolen OAuth credentials), the attacker can:

  • Read all user profiles in Azure Entra ID (names, emails, phone numbers, departments)
  • Read organizational hierarchy (who reports to whom, department structure)
  • Enumerate the entire directory (all 2,000+ employees)

ServiceNow Tables to Query for Discovery

To discover this type of integration, SecurityV0 needs to query the following tables. Each section shows both the API query and the UI navigation path.


1. OAuth Applications (oauth_entity)

What it contains: OAuth client applications registered in ServiceNow (stores client_id that links to Azure).

API Query:

Table: oauth_entity
Fields: sys_id, name, client_id, active, type, sys_created_by, sys_created_on
Query: active=true

UI Navigation:

All > System OAuth > Application Registry

Or use the Navigator filter: type oauth_entity.list

What you'll see in the UI:

ColumnDescription
NameDisplay name of the OAuth application
Client IDThe OAuth client_id (matches Azure App Registration app_id)
Client SecretHidden, but can be regenerated here
ActiveWhether the OAuth app is enabled
Type"OAuth API endpoint for external clients" for inbound, varies for outbound
Created byUser who created the OAuth app

Screenshot location: Click on any OAuth app to see full details including redirect URIs, token lifespans, and linked profiles.


2. OAuth Entity Profiles (oauth_entity_profile)

What it contains: Links OAuth applications to OAuth providers and defines grant types.

API Query:

Table: oauth_entity_profile
Fields: sys_id, name, oauth_entity, oauth_provider, grant_type
Query: [join to oauth_entity]

UI Navigation:

All > System OAuth > Application Registry > [Select an OAuth App] > OAuth Entity Profiles (related list)

Or directly: type oauth_entity_profile.list in Navigator

What you'll see in the UI:

ColumnDescription
NameProfile name
OAuth EntityLink to parent OAuth application
OAuth ProviderLink to provider (Microsoft, Okta, etc.)
Grant Typeclient_credentials, authorization_code, etc.
Default Grant UserUser to impersonate for client_credentials flow

3. OAuth Providers (oauth_entity_provider)

What it contains: External OAuth providers (Microsoft, Google, Okta) with their token endpoints.

API Query:

Table: oauth_entity_provider
Fields: sys_id, name, token_url, authorization_url
Query: nameLIKEmicrosoft OR token_urlLIKEmicrosoftonline

UI Navigation:

All > System OAuth > Application Registry
Then filter by Type = "OAuth Provider"

Or: type oauth_entity.list and add filter type=oauth_provider

What you'll see in the UI:

ColumnDescription
NameProvider name (e.g., "Microsoft Azure AD")
Token URLhttps://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Authorization URLFor auth code flow
Client IDServiceNow's client_id registered with the provider

4. Outbound REST Messages (sys_rest_message)

What it contains: Configurations for calling external REST APIs (like Microsoft Graph).

API Query:

Table: sys_rest_message
Fields: sys_id, name, rest_endpoint, authentication_type, sys_created_by
Query: rest_endpointLIKEgraph.microsoft OR rest_endpointLIKEmanagement.azure

UI Navigation:

All > System Web Services > Outbound > REST Message

Or: type sys_rest_message.list in Navigator

What you'll see in the UI:

ColumnDescription
NameREST message name (e.g., "Microsoft Graph API")
EndpointBase URL (e.g., https://graph.microsoft.com)
AuthenticationNone, Basic, OAuth 2.0, etc.
OAuth ProfileWhich OAuth profile to use for auth

To see HTTP methods: Click on a REST Message, then scroll to "HTTP Methods" related list.


5. REST Message HTTP Methods (sys_rest_message_fn)

What it contains: Individual HTTP operations (GET /users, POST /groups, etc.).

API Query:

Table: sys_rest_message_fn
Fields: sys_id, name, rest_message, http_method, rest_endpoint
Query: rest_message={sys_id from above}

UI Navigation:

All > System Web Services > Outbound > REST Message > [Select a message] > HTTP Methods (related list at bottom)

Or: type sys_rest_message_fn.list in Navigator

What you'll see in the UI:

ColumnDescription
NameMethod name (e.g., "GetUserByUPN")
HTTP MethodGET, POST, PUT, DELETE, PATCH
EndpointRelative path (e.g., /v1.0/users/${upn})
AuthenticationInherit from parent or override

6. Business Rules (sys_script)

What it contains: Server-side scripts triggered by table operations (insert, update, delete).

API Query:

Table: sys_script
Fields: sys_id, name, collection, when, condition, script, active, sys_created_by
Query: active=true^scriptLIKEAzure OR scriptLIKEGraph OR scriptLIKEEntra

UI Navigation:

All > System Definition > Business Rules

Or: type sys_script.list in Navigator

To find Azure-related rules: Use the search/filter to search in the Script field for "Azure", "Graph", "REST", or specific REST message names.

What you'll see in the UI:

ColumnDescription
NameRule name
TableWhich table triggers this rule (incident, task, etc.)
Whenbefore/after/async
Insert/Update/Delete/QueryWhich operations trigger it
ActiveIs it enabled
ScriptThe actual code (click to view)

7. Script Includes (sys_script_include)

What it contains: Reusable server-side JavaScript classes/functions called by Business Rules.

API Query:

Table: sys_script_include
Fields: sys_id, name, api_name, script, active, sys_created_by, sys_updated_by
Query: active=true^scriptLIKERESTMessage OR scriptLIKEOAuthClient

UI Navigation:

All > System Definition > Script Includes

Or: type sys_script_include.list in Navigator

What you'll see in the UI:

ColumnDescription
NameClass/function name
API NameGlobal API name to call from other scripts
Client CallableCan browser-side scripts call this
ActiveIs it enabled
ScriptThe actual code
Created by / Updated byOwnership trail

Tip: Search for script includes that reference RESTMessageV2, sn_ws.RESTMessageV2, or specific OAuth entity names.


8. Scheduled Jobs (sysauto_script)

What it contains: Time-based automations that run on a schedule.

API Query:

Table: sysauto_script
Fields: sys_id, name, script, run_as, active, sys_created_by
Query: active=true^scriptLIKEAzure OR scriptLIKEGraph

UI Navigation:

All > System Definition > Scheduled Jobs > Scheduled Script Executions

Or: type sysauto_script.list in Navigator

What you'll see in the UI:

ColumnDescription
NameJob name
RunSchedule (Daily, Weekly, etc.)
Run asWhich user context it executes under
ActiveIs it enabled
Next actionWhen it will run next
ScriptThe code to execute

Quick Navigation Cheat Sheet

What you're looking forNavigator filter
OAuth Applicationsoauth_entity.list
OAuth Profilesoauth_entity_profile.list
REST Messagessys_rest_message.list
REST HTTP Methodssys_rest_message_fn.list
Business Rulessys_script.list
Script Includessys_script_include.list
Scheduled Jobssysauto_script.list
Userssys_user.list
User Rolessys_user_has_role.list

Pro tip: In any list view, right-click column headers to add/remove columns, or use the filter icon to search within specific fields.


Complete Discovery Query Chain

┌─────────────────────────────────────────────────────────────────────────────┐
│ DISCOVERY CHAIN: Find all ServiceNow → Azure integrations │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Find Azure-related REST Messages │
│ sys_rest_message WHERE rest_endpoint LIKE '%graph.microsoft%' │
│ OR rest_endpoint LIKE '%management.azure%' │
│ │
│ 2. For each REST Message, find authentication config │
│ → What OAuth entity does it use? │
│ → What credentials (client_id) are configured? │
│ │
│ 3. Find OAuth Entity by client_id │
│ oauth_entity WHERE client_id = {value} │
│ → Who created it? (sys_created_by) │
│ → Is it active? │
│ │
│ 4. Find what CALLS this REST Message │
│ sys_script WHERE script LIKE '%{rest_message_name}%' │
│ sys_script_include WHERE script LIKE '%{rest_message_name}%' │
│ sysauto_script WHERE script LIKE '%{rest_message_name}%' │
│ │
│ 5. Build execution chain │
│ Business Rule → Script Include → REST Message → OAuth Entity │
│ │
│ 6. Correlate to Azure │
│ oauth_entity.client_id = Azure App Registration.app_id │
│ │
└─────────────────────────────────────────────────────────────────────────────┘

What SecurityV0 Detects

Finding 1: Orphaned Cross-Service Integration

TRIGGER: OAuth Entity "sn-ticket-router-oauth" created by mike.johnson
mike.johnson account status: INACTIVE in ServiceNow
Azure SP owner mike.johnson@contoso.com: DELETED in Entra ID

EXPLANATION:
This outbound integration to Microsoft Graph was created by
mike.johnson, who is no longer active in either system.

The integration continues to execute via Business Rule
"Auto-route identity tickets via Entra" on every identity ticket.

No one is accountable for this cross-service execution path.

EVIDENCE:
- ServiceNow OAuth entity: sn-ticket-router-oauth
- Azure App Registration: sn-ticket-router
- Client ID: b085873d-e521-4e2d-9ae6-92554800c8de
- Last execution: 2 minutes ago
- Owner (both sides): MISSING

Finding 2: High-Privilege API Access Without Owner

TRIGGER: Azure SP has User.Read.All + Directory.Read.All
No owner assigned
Called from ServiceNow Business Rule

BLAST RADIUS:
- Can read all 2,000+ user profiles
- Can enumerate entire organizational hierarchy
- Can access department, manager, location for all employees

REMEDIATION:
1. Assign owner on Azure side (App Registration)
2. Assign owner on ServiceNow side (OAuth Entity, Script Include)
3. Review if Directory.Read.All is necessary (User.Read.All may suffice)
4. Set up alerting for unusual query patterns

Key Insight

Scenario 01 (Azure → ServiceNow): Azure Function calls into ServiceNow to create tickets.

Scenario 02 (ServiceNow → Azure): ServiceNow calls out to Azure to look up user data.

Both create cross-service execution paths where:

  • An autonomous identity (OAuth app / Service Principal) executes continuously
  • Ownership can decay on either side (or both)
  • Scope can drift in either system
  • Existing tools only see "their" side of the integration

SecurityV0 connects both sides to show the complete execution path, blast radius, and ownership chain.