Earl_of_Duke
Earl_of_Duke

Reputation: 358

Postman not connecting to Dynamics365 API using Oauth client credentials, console app working using same details

I am trying to connect with Postman to Dynamics365 CRM REST API. Although I obtain a token successfully without login using Grant Type client credentials I then get a 401 error when doing a sample GET to the API. My console application is working successfully however and is not prompting the user for login (I don't want a login prompt to appear).

I have: 1. Registered the app in Azure AD, 2. Created the client secret 3. Created the application user in Dynamics and linked via the Application ID to App from step 1

I've done this with two different apps and two different application users and get the same result in Postman i.e. Token retrieved but 401 error on GET.

The console app below is working with the same credentials, would appreciate any input on what is missing in the Postman config

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Net.Http.Headers;
using System.Net.Http;
using Newtonsoft.Json.Linq;
namespace ConsoleApp8
{
    class Program
    {
        static void Main(string[] args)
        {
            const string ResourceId = "https://myurldev.crm4.dynamics.com/api/data/v9.1";
            Task<AuthenticationResult> t = GetUserOAuthToken();
            t.Wait();
            string accessToken = t.Result.AccessToken;
            Console.WriteLine("ACCESS TOKEN \n\n" + accessToken);
            Console.WriteLine("\n\n Please any key to display content of the blob");

            //Console.ReadKey();

            using (HttpClient httpClient = new HttpClient())
            {
                httpClient.BaseAddress = new Uri(ResourceId);
                httpClient.Timeout = new TimeSpan(0, 2, 0);  // 2 minutes  
                httpClient.DefaultRequestHeaders.Authorization =
                    new AuthenticationHeaderValue("Bearer", accessToken);
                //Send the Get Incident request to the Web API using a GET request. 
                var response = httpClient.GetAsync("/incidents",
                        HttpCompletionOption.ResponseHeadersRead).Result;
                if (response.IsSuccessStatusCode)
                {
                    //Get the response content and parse it.

                    JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result);


                    string title = (string)body["title"];
                    Console.WriteLine("Incident title is : {0}", title);
                }
                else
                {
                    Console.WriteLine("The request failed with a status of '{0}'",
                           response.ReasonPhrase);
                }
            }

            /*
            // Use the access token to create the storage credentials. 

            TokenCredential tokenCredential = new TokenCredential(accessToken);
            StorageCredentials storageCredentials = new StorageCredentials(tokenCredential);

            // Create a block blob using those credentials 

            CloudBlockBlob blob = new CloudBlockBlob(new Uri("https://placeholderURL/SalesOrder.json"), storageCredentials);
            using (var stream = blob.OpenRead())
            {
                using (StreamReader reader = new StreamReader(stream))
                {
                    while (!reader.EndOfStream)
                    {
                        Console.WriteLine(reader.ReadLine());
                    }

                }
            }
            Console.WriteLine("\n\n Please any key to terminate the program");
            Console.ReadKey();*/
        }

        static async Task<AuthenticationResult> GetUserOAuthToken()
        {
            const string ResourceId = "https://myurldev.crm4.dynamics.com/";
            const string AuthInstance = "https://login.microsoftonline.com/{0}/";
            const string TenantId = "XXXX-DYNAMICS_TENANT_ID-XXXXX"; // Tenant or directory ID 

            // Construct the authority string from the Azure AD OAuth endpoint and the tenant ID.  
            string authority = string.Format(System.Globalization.CultureInfo.InvariantCulture, AuthInstance, TenantId);
            AuthenticationContext authContext = new AuthenticationContext(authority);
            ClientCredential cc = new ClientCredential("XXXX_APPLICATION_ID_XXXX", "XXXXX_CLIENT_SECRET_XXXX");

            // Acquire an access token from Azure AD.  
            AuthenticationResult result = await authContext.AcquireTokenAsync(ResourceId, cc);
            return result;
        }
    }
}

POSTMAN TOKEN VARIABLES

POSTMAN REQUEST AND RESPONSE

I had already added the following permissions to my APP Dynamics Permissions

This is the response when I analyse the token in JWT.io JWT.io Token Debug

Upvotes: 0

Views: 1462

Answers (1)

Tony Ju
Tony Ju

Reputation: 15609

It seems that Dynamics CRM only support delegated permission which allow the application to access Common Data Service acting as users in the organization. This means client credentials is not appropriate here.

enter image description here

However, you said that you can use client credentials in console app. You can try with below request to get the access token.

enter image description here

Upvotes: 1

Related Questions