
- Post History
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
07-31-2023 02:52 AM - edited 07-31-2023 02:55 AM
ServiceNow Table API. It is available baseline for all tables, easy to use ... and not so easy to grant/deny access and control what records and attributes can be used by each integration. Giving baseline roles, such as cmdb_read for CMDB, itil to access (many) Task tables etc., provide too much access for external integrations. Creating custom roles and access controls (ACLs) are not flexible at scale.
The challenge is to ensure the need-to-know principle for external integrations without heavy development using a configuration-type, data-driven approach.
The presented solution is a custom development that requires:
- 3 custom Tables (can be implemented with single custom table as well)
- 1 custom Scripted Web Service
- 1 custom Role
- Transaction log (custom, optional)
- Rate Limit Rules (baseline, optional)
What would be the outcome? The standard integration solution enabling a Table API-like data access with allow-listing of Tables, Attributes and Records that external integration can read, without use-case specific development.
Data Model
The following diagram represents the data model with custom tables (highlighted with light-red background) and their dependencies to other baseline tables.
Security
The entire solution shall be implemented as a Scoped Application, with the following roles as a minimum:
- <scope_name>.api_user, providing access to the Scripted WebService (API) itself
- <scope_name>.admin, with access to the backend configuration of the table/account subscriptions
Custom Tables
Data Table Configuration
This record contains the specification of allow-listed attributes that can be shared for the selected table (class). It is a generic configuration record that says: "only the selected attributes from this table can be shared through an integration". There can be more than one record for a single table (class), as there may be a need to share different data with different vendors. In this situation, it is important to subscribe only one Data Table Configuration to a single Vendor.
Attribute | Data type | Note |
Number | Auto-number, prefix DTC | Read-only |
Table | Reference to Table [sys_db_object] | Mandatory |
Description | String (4000) | |
Attributes | List, reference to Dictionary Entry [sys_dictionary] | Mandatory, showing only attributes related to the selected Table, without Collection and Empty attributes |
Chunk size | Integer | Mandatory, default: 1000 |
Active | True/False |
Account Subscription
This record contains a list of Data Table Configuration subscribed to a single Vendor Integration Account (user account). In practice, it defines what Tables, Record and Attributes are accessible for the specified Integration Account.
Attribute | Data type | Note |
Number | Auto-number, prefix DTS | Read-only |
Integration Account | Reference to User [sys_user] | Mandatory |
Description | String (4000) | |
Active | True/False | |
Subscribed tables | Related list to Subscribed Table |
Subscribed Table
This record contains the configuration of the Data Table Configuration record for a subscribed Integration account. The key element is a Data filter that restricts what records belong to the Vendor and should be returned.
Attribute | Data type | Note |
Number | Auto-number, prefix SUB | Read-only |
Account Subscription | Reference to Account Subscription | Mandatory |
Data Table Configuration | Reference to Data Table Configuration | Mandatory |
Active | True/False | |
Data filter | Conditions |
The Data Filter should target a table specified in Data Table Configuration.Table attribute |
Scripted Web Service
A custom Scripted Web Service should consume the configuration tables mentioned above. The Web Service should be an entry point for all integrations, protected by the custom role <scope_name>.api_user. The custom role should be the only one role granted to the external integration account.
The following methods should be part of the custom Scripted Web Service:
- getSubscriptions, providing a list of subscribed tables and their attributes
- getData, providing the data itself
getSubscriptions Method
The getSubscriptions method returns a complete list of subscribed Tables and Attributes, for the given Integration Account. There are no input parameters needed. The Scripted REST Resource will read tables subscribed to the Account used and provide:
- List of tables (Data Table Configuration.Table)
- For each Table list of Attributes (Data Table Configuration.Attributes)
Example of the returned JSON:
{"result": [
{
"table_name": "cmdb_ci_win_server",
"display_name" : "Windows Server",
"url": "<URL to the interface>",
"attributes": "name,install_status,operational_status,fqdn"
},
{
"table_name": "cmdb_ci_service_discovered",
"display_name" : "Application Service",
"url": "<URL to the interface>",
"attributes": "name,operational_status,busines_criticality,change_control,assignment_group"
}
]}
getData Method
The getData method returns data for the selected Table and defined Attributes. This interface internally calls the baseline Table API of the given table (https://<instance_name>.service-now.com/api/now/table/<table_name>?<parameters>), with additional parameters (sysparm_fields, sysparm_limit etc.) based on the configuration tables. The getData Resource should expect the following input parameters:
Parameter | Data type | Notes |
table_name | String | Mandatory |
page_index | Integer | Optional, default: 0 |
last_update | DateTime | Optional |
filter | String |
Optional (encoded query) |
Once executed, the getData method should call the internal Table API to provide values:
- The input parameter "table_name", together with the account used for integration, is used to identify the "Subscribed Table";
- if the required table is NOT subscribed, HTTP 403 (Forbidden) response is returned;
- if the required table IS subscribed, the baseline Table API call should be constructed and executed with an internal account having the necessary permissions (e.g. admin-level account).
The baseline Table API call should be constructed as follows:
- https://<instance_name>.service-now.com/api/now/table/<target_table>?<parameters>
- <target_table> = Subscribed Table.Data Table Configuration.Table OR „table_name“ input parameter
- <parameters> = as defined in the next table
URL parameter | Value | Note |
sysparm_display_value | all | |
sysparm_exclude_reference_link | true | |
sysparm_suppress_pagination_header | true | |
sysparm_fields | Subscribed Table.Data Table Configuration.Attributes | |
sysparm_limit | Subscribed Table.Data Table Configuration.Chunk size | |
sysparm_offset | page_index (input parameter) | |
sysparm_query | Subscribed Table.Data Filter + <filter (input parameter)> + sys_updated_on>=<last_update (input parameter)> + ORDERBY sys_created_on |
Records must always be sorted to provide consistent results due to pagination. For this reason, sorting is based on the sys_created_on value. Part of the query "sys_updated_on" is added only when "last_update" is provided as the input parameter; otherwise, do not include it. When the custom „filter“ value is provided, ensuring that no „^NQ“ (new query) condition is part of the value is essential. Otherwise, it may override the specified record filter. |
The baseline Table API response content should be returned by the getData method. This ensures the same response structure as the baseline Table API provides.
Example of returned JSON with two records and two attributes (install_status, name), equivalent to the following baseline Table API call: https://<instance_name>.service-now.com/api/now/table/cmdb_ci_server?sysparm_display_value=all&syspa...
{"result": [
{
"install_status": {
"display_value": "Installed",
"value": "1"
},
"name": {
"display_value": "Service-now Production Sacramento",
"value": "Service-now Production Sacramento"
}
},
{
"install_status": {
"display_value": "Installed",
"value": "1"
},
"name": {
"display_value": "Service-now Production San Diego",
"value": "Service-now Production San Diego"
}
}
]}
Optional Features
There are two main optional features that should be considered:
Logging of all transactions
For the audit purpose, it is recommended to log all inbound transactions, optionally including the response provided.
Rate limits
To ensure the performance of your instance, you may consider the implementation of Rate Limits (https://docs.servicenow.com/bundle/tokyo-application-development/page/integrate/inbound-rest/concept...). With Rate Limits in place, you may prevent excessive data extraction and overload of semaphores.
Conclusion
The presented solution is custom development. However, once developed, it allows granular data-driven access control for external integrations. There is no need to develop integration-specific ACLs or other security controls. Develop once, use many times – control by the data directly in production.
- 1,921 Views
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hi, @David Skowronek
Great looking design.
Since this is designed as a scoped application, I assume you have implemented this?
Would you be able to share the application?

- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Report Inappropriate Content
Hello, @Tapio Silvera . Unfortunately, I cannot share the implemented solution. I has been implemented by several customers, but always inside their own scope.