This article walks through a practical, end-to-end approach for calling the ServiceNow REST API from SAS using PROC HTTP and OAuth 2.0. You’ll learn how to:
The examples assume Base SAS (SAS 9 or SAS Viya) with PROC HTTP available. All code is available as a reference implementation on GitHub in the sascommunities/sas-dummy-blog project.
Want to follow along? If you have a "NOW" signin for ServiceNow, visit the ServiceNow developer portal, where you can request a development environment for testing! This allows you to try these steps and get them working before pursuing the process in your own environment.
Credit: this article was inspired by the exchange in this discussion post: PROC HTTP and ServiceNow oauth Token.
Before you write any SAS code, you need a small amount of setup in ServiceNow. These instructions assume that you are familiar with the techniques for navigating ServiceNow menus and configuration. I found this helpful: a video tutorial about ServiceNow API and Postman. Postman is a REST API client in just the same way we will be using PROC HTTP. (Keep in mind that ServiceNow releases new versions every 6 months or so, so some steps and screenshots might look slightly different.)
Important: Treat the client secret like a password. Store it securely (for example, in a secured file in your home directory, or folder with "chmod 600" applied).
In these examples, we assume that you store your ServiceNow app "secrets" in a CSV file that only you can access. The following SAS code comprises three main steps:
%let SN_INSTANCE=https://dev12345.service-now.com;
/* Store the credentials in a secure area */
/* assumes you have a CSV file here named service-now-creds.csv */
/* with client-id, client-secret, username, password */
%let credsLoc = /u/&sysuserid./.creds/sn;
filename creds "&credsLoc";
/* ===== Build application/x-www-form-urlencoded body ===== */
filename tok temp;
data _null_;
infile creds(service-now-creds.csv) dsd firstobs=2;
length client_id $ 40 client_secret $ 40 username $ 40 password $ 250 out $ 500;
length d1-d5 $ 600;
input client_id client_secret username password;
d1 = "grant_type=password";
d2 = catt('client_id=',urlencode(trim(client_id)));
d3 = catt('client_secret=',urlencode(trim(client_secret)));
d4 = catt('username=',urlencode(trim(username)));
d5 = catt('password=',urlencode(trim(password)));
out = catx('&',d1,d2,d3,d4,d5);
;
/* Store API input data in macro var */
call symputx('SN_CRED',out);
run;
/* ===== Call token endpoint ===== */
filename tokresp temp;
proc http
url="&SN_INSTANCE./oauth_token.do"
method="POST"
in="&SN_CRED"
out=tokresp
ct="application/x-www-form-urlencoded";
run;
%if (&SYS_PROCHTTP_STATUS_CODE. = 200) %then %do;
/* ===== Parse JSON and extract access_token ===== */
/* Save token and refresh token in secure area for next access */
libname tokjson json fileref=tokresp;
filename savetok "&credsLoc./sntoken.json";
/* token fields often appear in tokjson.root */
data _null_;
rc = fcopy('tokresp','savetok');
set tokjson.root;
if not missing(access_token) then do;
call symputx('snAccessToken', access_token, 'G');
end;
run;
/* Debugging only */
%put NOTE: Token acquired successfully;
libname tokjson clear;
filename savetok clear;
%end;
filename tokresp clear;
(This logic is encapsulated in the %getSNaccessToken macro in the reference code on GitHub.)
With the access token in hand (stored in &snAccessToken in our example code), we can use PROC HTTP to call a ServiceNow API -- for example, to query the Incident table. Note that the ServiceNow documentation and the REST API Explorer tool can help you to craft useful API calls that retrieve just the data fields that you need.
/* Sample API Call */
/* Query the Incident table with limited parms */
filename results temp;
proc http
url="&SN_INSTANCE./api/now/table/incident?sysparm_fields=number%2Cresolved_by%2Copened_by%2Cshort_description&sysparm_limit=10"
method="GET"
out=results
ct="application/json"
oauth_bearer="&snAccessToken.";
run;
libname incident json fileref=results;
proc print data=incident.result(obs=5);
var number short_description;
run;
libname incident clear;
filename results clear;
Tip: the oath_bearer= option is a convenient shorthand instead of using the HEADERS statement:
headers "Authorization"="Bearer &snAccessToken.";
When successful, this example pulls back 5 records from the table and prints the INC numbers and descriptions:
(Comment: who needs a new Blackberry set up these days? I think ServiceNow is pranking us with the sample data.)
In the earlier step, our SAS code saved the ServiceNow access token and refresh token. Access tokens expire in a short time, usually about 30 minutes. But with the refresh token, we can obtain a new access token to use the APIs again, without having to re-supply our username and password in the API call.
The SAS code is almost the same as when we first obtain the access token, except this time we prepare the authentication call using the refresh token instead of user/password.
%let SN_INSTANCE=https://dev12345.service-now.com;
/* Store the credentials in a secure area */
/* assumes you have a CSV file here named service-now-creds.csv */
/* with client-id, client-secret, username, password */
%let credsLoc = /u/&sysuserid./.creds/sn;
/* Now use the Refresh token instead of username/password */
filename reftok "&credsLoc./sntoken.json";
libname tokjson json fileref=reftok;
/* token fields often appear in tokjson.root */
data _null_;
set tokjson.root;
if not missing(refresh_token) then do;
call symputx('refreshToken', refresh_token, 'G');
end;
run;
data _null_;
infile creds(service-now-creds.csv) dsd firstobs=2;
length client_id $ 40 client_secret $ 40 out $ 500;
length d1-d4 $ 600;
input client_id client_secret username password;
d1 = "grant_type=refresh_token";
d2 = catt('client_id=',urlencode(trim(client_id)));
d3 = catt('client_secret=',urlencode(trim(client_secret)));
d4 = catt('refresh_token=',urlencode(trim("&refreshToken.")));
out = catx('&',d1,d2,d3,d4);
;
/* Store API input data in macro var */
call symputx('SN_CRED',out);
run;
/* ===== Call token endpoint ===== */
filename tokresp temp;
proc http
url="&SN_INSTANCE./oauth_token.do"
method="POST"
in="&SN_CRED"
out=tokresp
ct="application/x-www-form-urlencoded";
debug level=3;
run;
%if (&SYS_PROCHTTP_STATUS_CODE. = 200) %then %do;
/* ===== Parse JSON and extract access_token ===== */
/* Save token and refresh token in secure area for next access */
libname tokjson json fileref=tokresp;
filename savetok "&credsLoc./sntoken.json";
data _null_;
rc = fcopy('tokresp','savetok');
set tokjson.root;
if not missing(access_token) then do;
call symputx('snAccessToken', access_token, 'G');
end;
run;
/* Debugging only */
%put NOTE: Token refreshed successfully.
libname tokjson clear;
filename savetok clear;
%end;
filename tokresp clear;
(This logic is encapsulated in the %refreshSNaccessToken macro in the reference code on GitHub.)
A typical production pattern looks like this:
This approach avoids embedding passwords in scheduled jobs while still providing reliable API access.
Nearly 200 sessions are now available on demand with the SAS Innovate Digital Pass.
Explore Now →The rapid growth of AI technologies is driving an AI skills gap and demand for AI talent. Ready to grow your AI literacy? SAS offers free ways to get started for beginners, business leaders, and analytics professionals of all skill levels. Your future self will thank you.