Having difficulty integrating Azure DevOps REST API with ServiceNow, attempting to use refresh token to gain a new access token
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎06-15-2021 12:54 AM
I have managed to setup some connectivity between ServiceNow and Azure DevOps. Here is the quick summary of what I've done:
- Setup a third party OAuth provider in System oAuth - Application Registry
- Set the Default Grant Type of Authorization Code, scopes and a customised oAuthUtil Script (needed this to get the oAuth Token link to work when setting up the REST Message
- Default Profile has the correct entity scope set on it too.
- Setup a System Web Services - REST Message thus:
Get oAuth Token link works here, puts a refresh token (times out in 100 days time) and an access token (times out in 30 minutes) into System oAuth - Manage Tokens. The test link then works for the 30 minutes the access token is active for.
Here's the problem, after 30 min when I click the test link, I get an error "User Not Authenticated. Could not retrieve a new access token with the refresh token. invalid_request, Missing parameters: access_token"
After having watched Josh Nerius's Live Coding youtubes 2017 around oAuth, it looks as though on every invokation of the test, the access token should be refreshed by using the refresh token and I can't get ServiceNow to replicate this behaviour. (The main difference between Azure DevOps REST API and Office 365 appears to be no "offline" capability.
If I click on Link "Get oAuth Token" I can manually refresh tokens and the REST calls work for another 30 minutes.
I'm thinking that I need to include something specific in the request body as the message is sent out to Azure DevOps as per the Azure DevOps authentication here:
...but not sure how to amend the interceptRequestParameters function within (I can add URI parameters and have got all of the other functions work as I think they should be.
OAuthUtilAF3 (latest attempt)-
//* Dont edit this script include. Best practise: Extend this script include and override the functions.
var OAuthUtilAF3 = Class.create();
OAuthUtilAF3.prototype = {
initialize: function(oauthContext) {
this.oauthContext = oauthContext;
},
interceptRequestParameters : function(requestParamMap) {
// Add/Modify request parameters if needed
gs.info(Date.now() + " 1");
var profGr = this.oauthContext.getOAuthProfile();
gs.info(Date.now() + " 1.15 " + profGr.getValue("grant_type"));
//var bodyContent = "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion={0}&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={1}&redirect_uri={2}";
requestParamMap.put("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
requestParamMap.put("client_assertion_type","urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
requestParamMap.put("access_token", "INSERT_CLIENT SECRET HERE");
requestParamMap.put("assertion",requestParamMap.get('code'));
gs.info(Date.now() + " 1.25 " + requestParamMap.get("code") );
gs.info(Date.now() + " 1.5" );
this.preprocessAccessToken(requestParamMap);
},
parseTokenResponse: function(accessTokenResponse) {
gs.info(Date.now() + " 2");
this.postprocessAccessToken(accessTokenResponse);
},
preprocessAuthCode: function(requestParamMap) {
gs.info(Date.now() + " 3");
requestParamMap.put('access_type','offline');
gs.info(Date.now() + " 3.5");
},
preprocessAccessToken: function(requestParamMap) {
gs.info(Date.now() + " 4");
requestParamMap.put("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
requestParamMap.put("client_assertion_type","urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
requestParamMap.put("client_assertion", "INSERT_CLIENT_HERE");
requestParamMap.put("assertion",requestParamMap.get('code'));
gs.info(Date.now() + " 4.25 code " + requestParamMap.get('code'));
gs.info(Date.now() + " 4.5");
},
postprocessAccessToken: function(accessTokenResponse) {
gs.info(Date.now() + " 5");
var contentType = accessTokenResponse.getContentType();
var contentBody = accessTokenResponse.getBody();
var paramMap = accessTokenResponse.getparameters();
gs.info(Date.now() + " 5.15 cb " + contentBody);
gs.info(Date.now() + " 5.15 ct " + contentType);
gs.info(Date.now() + " 5.15 pm " + JSON.stringify(paramMap));
if (contentType && contentType.indexOf('application/json') != -1) {
gs.info(Date.now() + " 5.25 " + JSON.stringify(accessTokenResponse.getBody()));
var tokenResponse = (new global.JSON()).decode(accessTokenResponse.getBody());
//var paramMap = accessTokenResponse.getparameters();
paramMap.put("access_token", tokenResponse["access_token"].toString());
paramMap.put("refresh_token", tokenResponse["refresh_token"].toString());
for (param in tokenResponse)
gs.info(Date.now() + " 5.5 bearer " + param + " " + tokenResponse[param].toString());
//paramMap.put(param, tokenResponse[param].toString());
}
},
type: 'OAuthUtilAF3'
};
I want to be able to either use the demonstrated refresh capability *or* have a scheduled job in the background effectively click that link every 29 minutes. Anyone seen similar or know of the code amendment I can do?
- Labels:
-
Integrations
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-21-2023 10:21 AM
What is
this._dumpParamMap("2.15", requestParamMap);
2.15 here? You used these kind of numbers at many places? what they are? please explain.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-27-2023 09:04 AM
Hello,
those numbers came from r3adm3's original script.
The function _dumpParamMap is used to dump the map into SN log. So it is not very important, you can remove all calls to this function. Same for _gsinfo.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-18-2022 05:35 AM
Hello r3adm3,
I am facing the exact same issue while the salesforce- ServiceNow integration (Note - I am using the methodology you are following for the integration). Tried the approach which is suggested by Christian but it didn't solve the issue for me. Can you please let me the approach you tried to solve this issue of refreshing the token. It could be a great help.
Appreciating your time for reading. Thanks.
Regards,
Rutvik.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-19-2022 01:08 PM
Hello Rutvik,
what I would do is read the Salesforce documentation: they should provide a documentation with all the keys needed to create the tokens. This is mandatory for all developers, not only ServiceNow (Microsoft provides one for Azure DevOps).
Then fill the requestParamMap with the keys. You have the _dumpParamMap function to see the map content.
Hope this helps.