How to make Dynamics 365 Web API queries using OAuth?

, , ,

Related to my previous blog post, I thought that I would write a new post about Dynamics 365 (on-premise) Web API, ADFS 3.0 and OAuth. This same applies for Dynamics 365 online as well because the Web API is designed to be used by OAuth when Dynamics 365 is either online or configured to IFD-mode with one exception: in this scenario described in my blog post, I use ADFS 3.0 installed on one of my local Windows Server 2012 R2 boxes. Naturally in online scenario, Azure AD would be used for authorization. This actually makes quite significant difference as per my findings. It seems that ADFS 3.0 poses quite a few restrictions in terms of OAuth usage.

The scenario this time is such that I needed to simulate an external application making a request against Dynamics 365 Web API. Initially I thought of doing this whole simulation using the SOAPUI tool but I was not able to get it working. It seems that at least the SOAPUI tool for obtaining the OAuth access token always sets the response_type parameter to value “token” instead of “code” which is needed in my case. So, because of that, I ended up doing this simulation in the following sequence of steps and tools:

  1. Register client application to ADFS using PowerShell
  2. Make an HTTP GET request using browser against the proper OAuth endpoint in ADFS to obtain the OAuth authorization code
  3. After getting the authorization code from the second step, do HTTP POST request against another OAuth endpoint to obtain the OAuth access token. For this step, I used the Fiddler tool.
  4. Use the OAuth access token from step 3 to make the actual Dynamics 365 Web API request. For this step, I used SOAPUI tool.

Below these steps are described in more detail.

Register client application

I pushed my bravery to the limits and started PowerShell in admin mode. The command line entry I used was as following:

Add-AdfsClient -ClientId 017BEFF0-603E-40E7-B19B-94834983CFEE -Name TestOauth2_2 -RedirectUri https://sts.domain.com/adfs/ls/IdpInitiatedsignon.aspx

ClientId: this can be pretty much any GUID which is unique within this ADFS instance. In Azure AD, the client application registration assigns the ClientId automatically
RedirectUri: this is the one which is used to authenticate the user in ADFS

Obtain OAuth authorization code

So, I fired my good old friend and also started IE and typed the following to the address bar:

https://sts.domain.com/adfs/oauth2/authorize?response_type=code&client_id=017BEFF0-603E-40E7-B19B-94834983CFEE&redirect_uri=https%3A%2F%2Fsts.domain.com%2Fadfs%2Fls%2FIdpInitiatedsignon.aspx&resource=https%3A%2F%2Fcrmtenant.domain.com

response_type: with this you specify that you want the authorization code as response
client_id: this must be the same as in step 1 above
redirect_uri: again, the same as in step 1 above
resource: the server or service that the client wants to access. In this case, that is the Dynamics 365 CRM tenant URL

It must be noted here that the URL values must be URL encoded in this request.

When hitting the Enter key after adding the above to the browser address bar, you should see some type of an authentication window. After entering proper credentials, you will see success message in the browser and the browser address bar will contain the authorization code which you need in the next step.

Obtain OAuth access token

There are probably other tools and truths out there than Fiddler but I haven’t found one. So, because of that, I decided to use Fiddler. It has the handy HTTP request composer which I used to make the HTTP POST request against the proper ADFS OAuth endpoint. The request in raw format looks as following:

POST https://sts.domain.com/adfs/oauth2/token/ HTTP/1.1

User-Agent: Fiddler

Content-Type: application/x-www-form-urlencoded

Host: sts.domain.com

Content-Length: 646

grant_type=authorization_code&client_id=017BEFF0-603E-40E7-B19B-94834983CFEE&code= 6ZRcIsJYk5UAmJg&resource=https%3A%2F%2Fcrmtenant.domain.com%2Fapi%2Fdata%2Fv8.1%2F&redirect_uri=https%3A%2F%2Fsts.domain.com%2Fadfs%2Fls%2FIdpInitiatedsignon.aspx

grant_type: the OAuth2 grant type (flow) which is used. This is now the part which I mentioned on the top part of this blog post. It turns out that ADFS 3.0 has several restrictions due to which not all the OAuth2 grant types are supported. One of the underlying reasons to that is that ADFS 3.0 does not support client secrets which are used in several grant types. As far as I know, this is changed in ADFS v. 2016 but then again, Dynamics 365 on-premise does not support ADFS v. 2016. That does not mean that Dynamics 365 on-premise would not work with ADFS v. 2016 but officially it is not supported. So, long story short, I will use here the one grant type which ADFS 3.0 supports and that is called authorization code. More details about OAuth2 grant types can be found for example here: https://alexbilbie.com/guide-to-oauth-2-grants/
client_id: again, the same which is used in earlier steps
code: this is the authorization code obtained in the previous step
resource: the CRM tenant’s Web API URL
redirect_uri: again, the same as above

After successful execution of this HTTP POST request, Fiddler shows the access token which is returned in the JSON format.

Next I fully utilized the famous copy&paste methodology and copied the access token from Fiddler response screen and pasted that to the SOAPUI authentication box.

The only thing left to do was to compose the Dynamics 365 Web API request in SOAPUI as shown below. The results were returned nicely:

Results

Summary

Even though pretty much everything is going to cloud nowadays, I decided to write this blog post related to the on-premise scenario. The reasoning for that is that…hmmm…because it seems that doing things on-premise makes things more interesting. In Azure, there are more or less UI wrappers for everything and it is a bit challenging to see what’s happening under the hood. As we have a saying in Riihimäki jungles: #eilistäpäivää