MS Graph / OAuth 2.0 Integration - Best practice questions and issues

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎02-05-2020 01:48 PM
Hi, I really hope someone who has had some success properly implementing the Authorization code flow for MS Graph API can point me in the right direction as I feel I am missing some bits to fully understand the integration.
I have built my integration with MS Graph and it is working fine. I am requesting Access tokens, getting those and successfully using the Graph API to interact with e.g. Calendars or Mail. So you might ask, what's wrong?
Well, it appears to be running fine but I feel it is still not perfect. It really depraves me of valuable sleep. So, let me break down the issues I feel I have:
1. In the Application Registry, I have added my application and then the OAuth Entity Profile, with the Grant Type "client_credentials" and the Scope "https://graph.microsoft.com/.default":
So why is ServiceNow forcing me to add the Grant type and Scope again when constructing my token request??? This works:
var tokenRequest = new sn_auth.GlideOAuthClientRequest();
tokenRequest.setGrantType('client_credentials');
tokenRequest.setScope('https://graph.microsoft.com/.default');
var oAuthClient = new sn_auth.GlideOAuthClient();
var tokenResponse = oAuthClient.requestTokenByRequest("Azure AD Token", tokenRequest);
BUT THIS DOESN'T and gives an error:
var tokenRequest = new sn_auth.GlideOAuthClientRequest();
var oAuthClient = new sn_auth.GlideOAuthClient();
var tokenResponse = oAuthClient.requestTokenByRequest("Azure AD Token", tokenRequest);
OAuthProblemException{error='invalid_request', description='AADSTS900144: The request body must contain the following parameter: 'grant_type'.
OAuthProblemException{error='invalid_request', description='AADSTS90014: The required field
'scope' is missing from the credential. Ensure that you have all the necessary parameters for
the login request.
So, what's the point of adding all that to my Application Registry?
Or am I missing something here/using the wrong API?
2. Obviously, using "client_credentials", we cannot utilize the Refresh Token. The question is, is "Authorization Code" approach generally more recommended?
If yes, why? Can this approach work with "Application" permissions, or only with "Delegated" permissions? As I understand, Application > Delegated, right?
So, I created another Application Registry profile, this time with "Authorization Code" grant type, set everything up, created OAuth 2.0 Credential,
clicked the "Get OAuth token", got the pop-up where I had to click "Accept" - perfect. There is a new token in the Tokens table:
Now I get lost a bit and here are my questions:
- The pop-up with request for authorization appears only at the set-up and not every time the integration is fired, for every user, right? Sorry if that's a noob question.
It seems it would be really annoying if ServiceNow asked every user to click "Accept" before it can check their calendar. Then again, it seems to work based on impersonation...
- I understand that you only have to click the "Get OAuth token" link once and then the Refresh token should get a new Access token before it expires right?
In my case, the Access token expired after an hour and nothing else happened. I don't even know if I received the Refresh token - seems I did not. Also, why is the token field empty?
- how do I get the Refresh/Access tokens to run fully auto in the background? Is it not provided OOTB? Is there a specific API I have to use?
Do I need to write my own logic to get the Refresh Token, monitor the Token table to see if any Access token is active and if not, manually trigger
the generation of new Access token with Refresh token?
- What is the recommended way to trigger the REST service? Create a record in Outbound REST and link
it to the credentials? Or just trigger REST from script and build the whole Request header/body with authorization there?
Many thanks for any pointers in the right direction. It is hard to find valuable examples online, everyone seems to be using the "client_credentials" approach, I have not seen an example of setting up the Authorization Code end to end.
So I really hope someone can shed some light here. I even tried to install and run the Integration Hub spoke for "Exchange Online" as they use this approach there,
but could not see how it handles Refresh tokens...
Sorry for the long post but hopefully everyone can benefit from the answers/discussion 🙂 thanks!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎02-12-2020 08:53 AM
Hi,
You need NOT to REQUEST the token explicitly. Selecting the OAUth2.0 will automatically associate the token with the actual REST message calls.
On your regular/actual REST Message - ex: Get Calendar / Get User etc...
- Select Authentication Type = OAuth2.0
- OAuth profile = You need to create an OAuth entity profile (oauth_entity_profile) and assign to this field.
OAuth Entity Profile
Grant Type = Client Credentials
- OAuth provider = Reference from OAuth Entity (oauth_entity)
-
- OAuth Entity (oauth_entity)
-
- Client Id=XXXXXXXXX
- Client Secret = XXXXXXXX
- Default Grant Type = Client Credentials
- Token URL = XXXXXXXXXXX
- Refresh Token Lifespan= 3599 (or your specific)
- In Scope related list -> Scope = reference from OAuth Entity Scope List table - oauth_entity_scope( with value https://graph.microsoft.com/.default
The refresh token field on oauth_entity helps the system to refresh token when its life span finishes. All the tokens are stored in oauth_credential table.
Once this setup done, TEST from REST Message record.
In the code, just create the object for the REST Message (GetUser/Galendar etc....) and execute/call. This should automatically fetch the token and associate with the actual REST message call.
OAuth2 is meant to do this automatically behind the scenes.
Thanks

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎02-13-2020 12:15 AM
Hi,
thanks for your comments on this.
From what I understand, wihtin the client_credentials authorization flow you are not using the actual Refresh token, so I assume you are referring to the new Access token being automatically fetched when the time interval elapses?
Will the above "behind the scenes" token renewal only happen when I use the actual Outbound REST message or also if I construct the REST within script (RestMessageV2())?
I will try the setup you described above and post my findings here, my goal is to use as much OOB as possible so that would be really good if it worked.
BR,
Tomasz
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎02-13-2020 02:26 AM
Yes, It works from REST Message record and also from Script - using the RestMessageV2. Just do not specify anything about the authentication in script. By default, ServiceNow picks up the OAuth2 profile from the REST Message record.
New token will be fetched automatically, thats why there is a table which stores the tokens - oauth_credential

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎02-17-2020 01:47 AM
Thank you. It does seem to work with the Client Credentials grant type. The Access token was generated in the background.
Now I am trying to do the same but using Authorization Code grant type. I hope I am following the correct steps (of course I set up a new Oauth Entity with respective endpoints etc.).
1. I used the "Generate OAuth token" link under the REST Message
2. I was prompted to authenticate with Microsoft Online and entered my login/password/confirmed authoentication on my mobile.
3. The Access token was generated, it is valid for 1 hour. I tested the integration with the Access token and it worked.
4. Now the question is, when the hour passes - will ServiceNow regenerate the Access Token automatically based on the Refresh Token?? I sure hope so! We will see in an hour.