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

Tom Sienkiewicz
Mega Sage

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":

find_real_file.pngfind_real_file.png

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:
find_real_file.png
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!

 

17 REPLIES 17

OK it appears that a new Access token was not retrieved automatically. 

After the token expired, I had to click again the "Get OAuth token" link. I don't understand this - I was hoping everything would happen in the background as well.

Probably I have to write custom logic to refresh access tokens before they expire in this scenario.

 

Generally, its not recommended to use - Authorization Code Grant type for outbound integrations. How would you authorise on your mobile when systems trying to talk automatically.?!!!!

Client Credentials makes sense when ServiceNow trying to get authenticated to access the external webservice.

Well that depends on the business case I suppose.

Please note that if you get the Exchange Online Integration Hub spoke from the Store, they use exactly the Authorization Code grant type.

I actually managed to get it to work - the key was adding one more scope "offline_access" which causes the Refresh Token to be retrieved.

Then the user needs to give their permissions once at start-up and then it gets refreshed pretty much indefinitely.

I would agree that the Client Credentials/Application permissions are definitely more powerful and easier to set up 🙂 But some of MS Graph APIs only work with Delegated permissions so it all comes down to a specific case.

Thanks again for your input on this!

Cool. Good that you made it work. good luck

Hello,

I have done exactly the same thing but still get an error, when I log the token I can see that the resource param is missing, any chances you had the same issue ?

 

Thanks