Entra-ServiceNow Connector: Environment & API Reference
What exactly this connector queries, what permissions it needs, and what test data must exist for it to produce output.
Read architecture/11-platform-mental-model.md first for the conceptual model.
Credentials Required
# Azure Entra (app registration with client_credentials grant)
AZURE_TENANT_ID=<directory-tenant-id>
AZURE_CLIENT_ID=<app-registration-client-id>
AZURE_CLIENT_SECRET=<app-registration-secret>
# ServiceNow (basic auth API user)
SERVICENOW_INSTANCE=<instance-name> # e.g. "dev12345" (not full URL)
SERVICENOW_USERNAME=<integration-user>
SERVICENOW_PASSWORD=<password>
Azure Entra Permissions
Graph API (Application permissions, require admin consent)
| Permission | Required? | Purpose |
|---|---|---|
Application.Read.All | Yes | Discover all service principals |
Directory.Read.All | Yes | Read SP owners and directory context |
User.Read.All | Yes | Enrich owner records (status, department) |
AuditLog.Read.All | Recommended | Sign-in logs (execution evidence). Needs Azure AD P1/P2 licence |
ARM RBAC (assigned via Azure Portal → Subscription → IAM)
| Role | Scope | Purpose |
|---|---|---|
Reader | Subscription(s) | Enumerate Function Apps, resolve managed identities, read role assignments |
ServiceNow Permissions
The connector needs a read-only API user. Recommended: create a dedicated integration_user with custom ACL policy.
Tables queried (all read-only)
Core discovery (must have access):
| Table | What's fetched | Why |
|---|---|---|
oauth_entity | OAuth apps (client_id, name, active) | Cross-system correlation with Azure SPs |
sys_rest_message | Outbound REST endpoints | Discover external API connections |
sys_rest_message_fn | HTTP methods per REST message | Execution chain detail |
oauth_entity_profile | OAuth profile → entity mapping | Link credentials to connections |
sys_script | Business Rules (name, table, script) | Workload discovery + caller analysis |
sys_script_include | Script Includes (name, script) | Indirect execution chain callers |
sysauto_script | Scheduled Jobs | Recurring automation workloads |
sys_user | User accounts (name, email, active) | Owner lookup and validation |
Flow Designer (must have access if flows exist):
| Table | What's fetched | Why |
|---|---|---|
sys_hub_flow | Flow definitions (name, status, triggers) | Flow Designer workload discovery |
sys_hub_trigger_instance | Deployed flow triggers | What events trigger flows |
sys_hub_action_instance | HTTP/REST actions within flows | Egress detection |
sys_hub_flow_version | Flow version payloads | Connection alias resolution |
sys_connection | Connection aliases | Resolve URLs for flow HTTP actions |
Execution evidence (optional, scan continues without):
| Table | What's fetched | Why |
|---|---|---|
sys_flow_context | Flow execution records (last 30d) | Prove flow actually ran |
sys_trigger | Job trigger records | Prove scheduled job ran |
sys_log | Syslog entries from Script Includes | Structured execution evidence |
Trigger examples (optional, scan continues if denied):
| Table | What's fetched | Why |
|---|---|---|
incident | Recent incident records | Trigger provenance context |
change_request | Recent change records | Trigger provenance context |
sc_request | Recent catalog requests | Trigger provenance context |
Azure Graph API Calls (exact endpoints)
Service Principal Discovery
GET /v1.0/servicePrincipals
Paginates via @odata.nextLink. Filters to first-party SPs (same tenant). Currently fetches all then filters client-side.
Per matched SP (for each cross-system integration)
GET /v1.0/servicePrincipals/{sp_id}/owners
GET /v1.0/auditLogs/signIns?$filter=appId eq '{app_id}' and createdDateTime ge {30d_ago}&$top=100
GET /v1.0/servicePrincipals/{sp_id}/appRoleAssignments
GET /v1.0/servicePrincipals/{sp_id}/oauth2PermissionGrants
ARM (only if Function App endpoints detected)
GET https://management.azure.com/subscriptions?api-version=2020-01-01
GET https://management.azure.com/subscriptions/{sub}/providers/Microsoft.Web/sites?api-version=2023-12-01
GET https://management.azure.com/subscriptions/{sub}/providers/Microsoft.Authorization/roleAssignments?$filter=principalId eq '{id}'
GET /v1.0/servicePrincipals/{principal_id} (resolve managed identity)
Scan Phases (execution order)
Phase 1 — Cross-service identity binding:
- Fetch all Azure SPs (Graph)
- Fetch all ServiceNow OAuth entities (SN Table API)
- Match by
client_id=appId - For each match: fetch owners, sign-in logs, app roles, delegated permissions
Phase 2 — Execution chain discovery: 5. Fetch all ServiceNow REST Messages 6. For each: fetch HTTP methods, OAuth profiles 7. Fetch Business Rules, Script Includes, Scheduled Jobs 8. Trace callers: which scripts reference which REST Messages 9. Build execution chains (workload → script → REST message → OAuth → Azure SP)
Phase 3 — Flow Designer: 10. Fetch flow triggers, published flows 11. For each flow: fetch HTTP actions, resolve connection aliases 12. Classify egress targets
Phase 4 — Execution evidence:
13. Query sys_flow_context for recent flow runs
14. Query sys_trigger for recent job executions
15. Query sys_log for Script Include execution traces
Phase 5 — ARM resolution (if Function App detected): 16. Enumerate subscriptions → Function Apps → resolve managed identity 17. Fetch RBAC role assignments for managed identity
Test Data Requirements
For the connector to produce meaningful output in a dev environment, these must exist:
Minimum viable test data
- Azure SP with a known
appId(e.g.,560ad26b-...) - ServiceNow OAuth Entity with
client_idmatching thatappId - ServiceNow REST Message with
authentication_type: "OAuth2.0"pointing to that OAuth entity - ServiceNow Business Rule whose
scriptfield references the REST Message name (e.g.,RESTMessageV2('Graph - sn-router', 'post'))
This gives you one complete execution chain: BR → REST Message → OAuth → Azure SP.
For richer output
- Flow Designer flow (published, active) with an HTTP action calling an external URL
- Flow trigger (e.g.,
record_createonincident) - Recent
sys_flow_contextrecord (last 30 days) for that flow - Azure SP with an owner (so ownership findings can fire)
- Azure SP with app role assignments (so permission analysis works)
What the current dev environment has
Our Contoso Corp dev setup (SERVICENOW_INSTANCE=dev*, Azure tenant bcf375ed-...) contains:
- 24 Azure SPs (filtered from 122 total)
- 23 ServiceNow OAuth entities
- 3 matched cross-system integrations:
servicenow-openai-client↔Azure OpenAI OAuth - smsn-ticket-router↔Azure Graph OAuth Clientsn-ticket-router(second OAuth profile)
- 9 outbound REST Messages (4 matched to Azure, 5 unmatched)
- 83 Flow Designer flows with autonomous triggers
- 4 flows with recent execution records
- 1 Function App (
sv0-edr-stub-7165) with managed identity resolution
Evidence Completeness
The connector reports what data it could and couldn't access:
| Evidence Source | Status when working | Common failure |
|---|---|---|
| Azure SPs | available | Wrong AZURE_CLIENT_SECRET → auth failure |
| SP owners | available | Missing Directory.Read.All |
| Sign-in logs | available or unavailable_not_enabled | No P1/P2 licence, or missing AuditLog.Read.All |
| SN OAuth entities | available | Wrong SN credentials, or ACL blocks oauth_entity |
| SN execution chains | available | ACL blocks sys_script or sys_rest_message |
| SN flow executions | partial | ACL blocks sys_flow_context |
| ARM role assignments | available or unavailable_no_access | Missing Reader role on subscription |
Troubleshooting
"0 matched integrations" — No ServiceNow OAuth entity has a client_id matching any Azure SP appId. Create a test OAuth entity with a matching client_id.
"0 execution chains" — No Business Rules or Script Includes reference a REST Message name in their script body. Create a BR that calls RESTMessageV2('Your REST Message Name', 'post').
Sign-in logs empty — Either the SP hasn't authenticated in 30 days, or the tenant lacks Azure AD P1/P2 licence, or AuditLog.Read.All permission isn't granted.
"Failed to query sys_log: 400" — The ServiceNow user lacks read access to sys_log. Non-blocking; connector continues without syslog evidence.