6

I am building a console application in C#.
I want to make some calls to Microsoft Graph API to access and edit some Excel files in my SharePoint so I can automate some processes in my Organization.


The logic of the app is simple.

  1. I call Azure Active Directory to authenticate this console application using the clients credential flow which means we will provide a clientsID and AppKey. I took the clientsID and AppKey from Azure Active Directory > App Registrations. enter image description here
  2. Then I want to receive the access token and use this to make a GET Request to the Microsoft Graph API.
    E.g https://graph.microsoft.com/v1.0/me/

    But then response I get is this:

{
  "error": {
    "code": "InvalidAuthenticationToken",
    "message": "Access token validation failure. Invalid audience.",
    "innerError": {
      "request-id": "0a3ec**************",
      "date": "2019-10-15T13:54:33"
    }
  }
}

Below you will find the full code of my application with the two methods of getting the access token and calling the Graph API:

using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IdentityModel.Tokens;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using AuthenticationContext = Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext;

namespace Project_Budget
{
    class Program
    {
        private const string clientId = "14f1****************";
        private const string aadInstance = "https://login.microsoftonline.com/{0}";
        private const string tenant = "******.onmicrosoft.com";
        private const string resource = "https://graph.windows.net";
        private const string appKey = "IKV***********";
        static string authority = String.Format(CultureInfo.InvariantCulture, aadInstance, tenant);

        private static HttpClient httpClient = new HttpClient();
        private static AuthenticationContext context = null;
        private static ClientCredential credential = null;

        static void Main(string[] args)
        {
            context = new AuthenticationContext(authority);
            credential = new ClientCredential(clientId,appKey);

            Task<string> token = GetToken();
            token.Wait();
            //Console.WriteLine(token.Result + "\n");

            Task<string> graphCall = GetExcelFile(token.Result);
            graphCall.Wait();
            Console.WriteLine(graphCall.Result + "\n");
            Console.ReadLine();

        }

        private static async Task<string> GetExcelFile(string result)
        {
            string apiJsonResult = null;
            
            var apiCallString = "https://graph.microsoft.com/v1.0/me/";
         
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result);
            var getResult = await httpClient.GetAsync(apiCallString);

            if (getResult.Content != null)
            {
                apiJsonResult = await getResult.Content.ReadAsStringAsync();
            }

            
            return apiJsonResult;
        }

        private static async Task<string> GetToken() 
        {
            AuthenticationResult result = null;
            string token = null;
            result = await context.AcquireTokenAsync(resource, credential); //authentication context object
            token = result.AccessToken;
            return token;
        }

        
    }
}

I have given all the access required for the app to run. Also I run the query on Graph Explorer and runs properly.
enter image description here Why do I get this error on the console application?

2 Answers 2

4

Ideally, the resource should actually be

private const string resource = "https://graph.microsoft.com";

But you still need to select the scopes that you want to target in your application. The way you are doing it at the moment does seem to acquire/set the relevant scopes which is done for you by Graph Explorer.

I would suggest following this quick start tutorial on how to build a dot net core console app and you should be up and running in no time. It uses the MSAL library which works better than the ADAL library you are using in your scenario.

https://learn.microsoft.com/en-us/graph/tutorials/dotnet-core

Sign up to request clarification or add additional context in comments.

8 Comments

Hello! Thank you for taking the time to answer :) Now the response did change but to another error :/ { "error": { "code": "Request_ResourceNotFound", "message": "Resource 'b0d9c34b-3b87-4088-8066-546181bd067b' does not exist or one of its queried reference-property objects are not present.", "innerError": { "request-id": "bcde3683-e0e6-48db-a636-13d2bcc9e9ea", "date": "2019-10-16T08:45:59" } } } Since I am relatively new in .NET, I hope the guide will be not hard to grasp :)
The guide should be simple and quick to use. Please check it out and let me know how it goes.
The guide really did work as expected but I have 2 questions. 1) how can I avoid having to go to /devicelogin everytime I run the app and 2) is there a guide for all the Microsoft Graph SDK calls? I want to make a call like this but I don't know how to make it. e.g graph.microsoft.com/v1.0/sites/…
To avoid the /device login you can change the app to use a ConfidentialClientApplication rather than a PublicClientApplication. This link will help you with that learn.microsoft.com/bs-latn-ba/azure/active-directory/develop/…
In your case though the call will look something like var childrenCollectionPage = await _graphServiceClient.Sites["id"].Drive.Root.Children["children_id"].Children.Request().GetAsync();
|
1

I think the problem is with resource value you're specifying in your code.

Current Code: (This resource value https://graph.windows.net corresponds to Azure AD Graph API which is older API)

private const string resource = "https://graph.windows.net";

Try changing this to: (This resource value https://graph.microsoft.com corresponds to newer Microsoft Graph API which is the one you're calling in code that comes later var apiCallString = "https://graph.microsoft.com/v1.0/me/";)

private const string resource = "https://graph.microsoft.com";

1 Comment

Hello! Thank you for taking the time to answer :) Now the response did change but to another error :/ { "error": { "code": "Request_ResourceNotFound", "message": "Resource 'b0d9c34b-3b87-4088-8066-546181bd067b' does not exist or one of its queried reference-property objects are not present.", "innerError": { "request-id": "bcde3683-e0e6-48db-a636-13d2bcc9e9ea", "date": "2019-10-16T08:45:59" } } }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.