0
votes

I'm tring to instanciate a new instance of GraphServiceClient from Microsoft.Graph in the nugget manager.

What is already did:

  1. Create an ASP.NET Core 2.0 Console Application
  2. Add Micrososft.Graph from Nugget
  3. Register the app in the Azure AD portal to get the app secret ID (app password) and the app ID (client ID)
  4. Retreive the tenant ID (directory ID) from the Azure AD portal

Basicaly, here is the whole code from my ASP.NET Core 2.0 projet (Console Application) :

using Microsoft.Graph;
using Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace SendADUserListEmail.Services
{
    // Response object from Azure AD
    public class AzureADResponse
    {
        public string token_type { get; set; }
        public int expires_in { get; set; }
        public string access_token { get; set; }
    }

    /// <summary>
    /// Micrososf Graph vs Azure AD Graph :
    /// https://blogs.msdn.microsoft.com/aadgraphteam/2016/07/08/microsoft-graph-or-azure-ad-graph/
    /// 
    /// Introduction to the Azure Active Directory Graph API :
    /// https://www.red-gate.com/simple-talk/cloud/security-and-compliance/azure-active-directory-part-5-graph-api/
    /// 
    /// ULTIMATE TUTORIAL ABOUT MICROSOFT GRAPH APIS
    /// https://bytescout.com/blog/microsoft-graph-apis.html
    /// 
    /// Startup !!! TO READ !!! :
    /// https://github.com/microsoftgraph/msgraph-sdk-dotnet
    /// 
    /// Creating the application Client ID and Client Secret from Microsoft Azure new portal
    /// - Register an application on Azure Portal : 
    /// - 1. Accèder au portail
    /// - 2. Inscription d'application
    /// - 3. Voir Paramètres > Propriétés
    /// https://www.netiq.com/communities/cool-solutions/creating-application-client-id-client-secret-microsoft-azure-new-portal/
    /// 
    /// Microsoft App Registration Portal (alternative method to register an app) :
    /// https://apps.dev.microsoft.com
    /// 
    /// Microsoft Graph explorer (graph request tester) :
    /// https://developer.microsoft.com/en-us/graph/graph-explorer
    /// </summary>
    class GraphApiHelper
    {
        // Client
        GraphServiceClient GraphServiceClient = null;

        // Tenant ID (directory ID)
        private const string tenantId = "/*MY_TENANT_ID_FROM_AZURE_AD_PORTAL*/";
        // App ID (client ID)
        private const string appId = "/*MY_APP_ID_FROM_AZURE_AD_PORTAL*/";
        // Secret ID (app password)
        private const string appSecret = "/*MY_APP_SECRET_FROM_AZURE_AD_PORTAL*/";

        public void Connexion()
        {
            string url = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";
            string @params = $"client_id={appId}&" +
                "scope=User.Read&" +
                $"client_secret={appSecret}&" +
                "grant_type=client_credentials";

            try
            {
                string accessToken = "";
                string jsonStringResult = "";
                AzureADResponse response = new AzureADResponse();

                // Getting the access token from Azure AD
                using (WebClient webClient = new WebClient())
                {
                    webClient.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";

                    jsonStringResult = webClient.UploadString(url, @params);
                    response = JsonConvert.DeserializeObject<AzureADResponse>(jsonStringResult);

                    // Set the access token
                    accessToken = response.access_token;
                }

                // Initialize the Microsoft Graph client
                GraphServiceClient = new GraphServiceClient(new DelegateAuthenticationProvider((requestMessage) =>
                {
                    requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);

                    return Task.FromResult(0);
                }));
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message);
            }
        }

        public List<SystemUser> GetSystemUserList()
        {
            Connexion();

            return null;
        }
    }
}

I'm geting this error while trying to execute the post request with System.Net.WebClient :

string url = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";
string @params = $"client_id={appId}&" +
            "scope=User.Read&" +
            $"client_secret={appSecret}&" +
            "grant_type=client_credentials";

jsonStringResult = webClient.UploadString(url, @params);

The remote server returned an error: (400) Bad Request.

Based on this source: https://docs.microsoft.com/en-us/graph/auth-v2-service I'm suppose to receive something like this:

{
  "token_type": "Bearer",
  "expires_in": 3599,
  "access_token": 
  "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBP..."
}

What I need is the access token to initialize GraphServiceClient.

Any idea on why Microsoft Azure failed on this request?

1
You should look into ADAL (Azure AD authentication library). It can handle token acquisition for you.juunas
There are great quick starts here that show you how to get the very first calls working with ASP.NET developer.microsoft.com/en-us/graph/get-started/asp.net This will use the MSAL library rather than writing the code yourself to obtain an access token.Jeremy Thake MSFT

1 Answers

2
votes

You should follow juunas advice and use a library like ADAL which does that for you.

If you want to do the call to retrieve the token yourself, first verify that the problem comes from your code and not from your application registration by testing the same request from a tool like Postman. As you receive an error 400 it's probably that it's fro your code and that your request is not well formed.

I am not used to make http calls with a WebClient so I don't know what's wrong but I would have say it might be linked to the way you are handling your params. If I were you I would have used and HttpClient, you can find some samples of queries with form url encoded in stackoverflow (How to POST using HTTPclient content type = application/x-www-form-urlencoded).