Prerequisites
- A ServiceNow instance (e.g.,
acme.service-now.com) and a user with theadminrole to register an OAuth application - A ServiceNow user to authorize the connection whose roles allow reading the
sys_usertable (an admin, or a user withuser_admin), with an email on your organization's domain - ZLH running with a reachable callback URL
Step 1: Register an OAuth Application in ServiceNow
- In the filter navigator, open System OAuth > Application Registry
- Click New, then Create an OAuth API endpoint for external clients
- Fill in:
- Name:
ZombieLicenseHunter - Redirect URL:
{YOUR_ZLH_BASE_URL}/integrations/servicenow/callback - Client Secret: leave blank and ServiceNow generates one
- Leave the token lifespans at their defaults; ZLH refreshes the access token automatically
- Name:
- Submit, then reopen the record and add both scopes in the OAuth Entity Scopes related list:
useraccount— required for the authorization flowTable API— required for readingsys_userover REST; without it the connection succeeds but every sync fails
- Copy the Client ID and the Client Secret (click the lock icon on the field to reveal it)
Step 2: ZLH-Side Values
- The Redirect URL registered in Step 1 must be exactly
{YOUR_ZLH_BASE_URL}/integrations/servicenow/callback— protocol, host, port and path - Scope requested:
useraccount. Self-hosted deployments can override it withSERVICENOW_SCOPES; the scopes on the Application Registry record must cover whatever is requested - The Client ID and Client Secret are entered per integration in the UI, not in environment variables
Step 3: Connect via the ZLH UI
- In ZLH, navigate to Integrations > Add Integration
- Select ServiceNow
- Enter the Client ID and Client Secret from Step 1
- Enter your ServiceNow Instance as a full URL, e.g.
https://acme.service-now.com— a single.service-now.comhostname with no path or port - Click Connect — you are redirected to your instance to sign in and approve the application
- Approve the consent prompt; you are redirected back to ZLH with the integration active and a first sync queued
The connection and every sync run as the ServiceNow user who approved the prompt.
What Gets Synced
ZLH reads the sys_user table through the Table API, 100 records per page, and imports only records with active=true. For each user it captures:
- Email and the ServiceNow
sys_id(used as the stable identifier) - Roles, stored as the user's license types (one entry per role)
- Last login time
Not synced: deactivated users, groups, CMDB or asset data. Display names are not stored.
Troubleshooting
| Issue | Fix |
|---|---|
| "invalid instance: host must be under service-now.com" when saving | Enter the instance as https://<name>.service-now.com. Custom domains, paths, ports and query strings are rejected |
| ServiceNow shows an error page instead of the sign-in prompt | The Redirect URL on the Application Registry record does not match {YOUR_ZLH_BASE_URL}/integrations/servicenow/callback exactly |
| "Authorization failed: ..." after ServiceNow redirects back | ServiceNow refused the request. Check the Redirect URL and that useraccount is in the OAuth Entity Scopes, then retry |
| "Failed to complete OAuth handshake. Please check your credentials and try again." | The Client ID or Client Secret does not match the Application Registry record. Re-copy the secret (lock icon) and retry |
| "Access denied: you can only connect accounts from your organization's domain" | The ServiceNow user who approved the prompt has an email on a different domain from your ZLH login. Reconnect with a user on your domain |
Sync fails with servicenow: unexpected status 403 |
The token has no REST access. Add the Table API scope to the OAuth application, then click Reconnect on the integration's card on the ZLH home page |
Sync fails with servicenow: unexpected status 401 |
The refresh token expired or was revoked (see Refresh Token Lifespan on the record). Click Reconnect on the integration's card on the ZLH home page |
| Users are missing | Only records with active=true are imported. Deactivated users never appear |
| License types are empty for a user | The user's roles field is empty in ServiceNow. ZLH stores the roles exactly as ServiceNow reports them |