Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling Microsoft Graph API using user context/user token C#

I have a web application where user logins using the approach defined in this sample.

Now I want to call Microsoft Graph for this User. I have gone through many documents and it's very confusing how this should be done. This is what I have tried. I am not sure how to get the access token for this user.

//not sure about this
var token = await GetAccessToken();

var client = new GraphServiceClient(
    new DelegateAuthenticationProvider(
        requestMessage =>
        {
            requestMessage.Headers.Authorization =
                new AuthenticationHeaderValue("Bearer", token);

            return Task.FromResult(0);
        }));

var result = await client
    .Me
    .Request()
    .GetAsync();

As per this documentation, I need to use the Confidential Client Flow, but I am not sure if I need to use the Authorization Code flow or On-Behalf. I don't have access to the Authorization Code because of the approach I followed here.

ConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithTenantId(tenantId)
    .WithCertificate(clientCertificate)
    .Build();

Can someone please guide me on how to get the access token for the User? Should I be using Authorization Code flow or On-Behalf?

like image 723
user911 Avatar asked Feb 12 '20 00:02

user911


People also ask

How do you call a Microsoft Graph API?

Graph Explorer is a web-based tool that you can use to build and test requests using Microsoft Graph APIs. You can access Graph Explorer at: https://developer.microsoft.com/graph/graph-explorer. You can either access demo data without signing in, or you can sign in to a tenant of your own.

How do I call API access token?

The other way to make an API call with an access token is to add it to the request header. If using curl (a command line program that can be used for running API requests) you would specify the access token like this. Notice that the access_token is not in the URL at all. See the example on the API documentation site.


2 Answers

If you are following the sample listed above, you are on the right track. Following the tutorial, it shows to how call Microsoft Graph /me endpoint on behalf of the signed-in user. In this sample, the complexities of the ASP.NET Core middleware and MSAL.Net are encapsulated in the Microsoft.Identity.Web section of the tutorial.

You should already have a Web App registered in the Azure Portal. Now that you'll be calling Microsoft Graph, you'll need to register a certificate or secret for the Web App. Then in API permissions, ensure the Microsoft APIs tab is selected and choose the ones you want for Microsoft Graph.

Then, continue following the tutorial to enable MSAL to hook-up to the OpenID Connect events and redeem the authorization code obtained by the ASP.NET Core middleware. Once a token is received, MSAL will save it into a token cache (there is tutorial for this as well).

Keep following the tutorial and you'll add the GraphServiceClientFactory.cs which returns a GraphServiceClient. When it receives an access token for Microsoft Graph, it will make requests to Graph sending the access token in the header. The code is here:

public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
      string accessToken = await acquireAccessToken.Invoke();

      // Append the access token to the request.
      request.Headers.Authorization = new AuthenticationHeaderValue(
      Infrastructure.Constants.BearerAuthorizationScheme, 
      accessToken);
}

There is a bit more set-up to do, but follow the tutorial and you should be able to acquire a token and then use it to call Microsoft Graph.

like image 152
Jenny Avatar answered Nov 03 '22 12:11

Jenny


Note: you will need to reference your project with Microsoft.Graph

First, you will need a function to request for an access token

async Task<string> Post(string uri, Dictionary<string, string> parameters)
{
    HttpResponseMessage response = null;
    try
    {
        using (var httpClient = new HttpClient() { Timeout = TimeSpan.FromSeconds(30) })
        {
            response = await httpClient.PostAsync(uri, new FormUrlEncodedContent(parameters));
            if (!response.IsSuccessStatusCode)
                throw new Exception("post request failed.");

            var content = response.Content.ReadAsStringAsync().Result;
            if (string.IsNullOrWhiteSpace(content))
                throw new Exception("empty response received.");

            return content;
        }
    }
    catch (Exception e)
    {
        throw new Exception(error);
    }
}

Then you will need a model to handle the response from the web request

public class TokenRequest
{
    [JsonProperty("token_type")]
    public string TokenType { get; set; }

    [JsonProperty("access_token")]
    public string AccessToken { get; set; }
}

Then you will need a function to extract the data from the web request

TokenRequest GetAccessToken()
{
    // request for access token.
    var parameters = new Dictionary<string, string>();
    parameters.Add("client_id", "YOUR CLIENT ID");
    parameters.Add("client_secret", "YOUR CLIENT SECRET");
    parameters.Add("scope", "https://graph.microsoft.com/.default");
    parameters.Add("grant_type", "client_credentials");

    var response = Post(
        $"https://login.microsoftonline.com/{YOUR TENANT ID}/oauth2/v2.0/token",
        parameters).Result;

    return JsonConvert.DeserializeObject<TokenRequest>(response);
}

Then request for an authenticated graph api client

GraphServiceClient GetClient()
{
    var tokenRequest = GetAccessToken();
    var graphClient = new GraphServiceClient(
        new DelegateAuthenticationProvider(
            async (requestMessage) => {
                await Task.Run(() => {
                    requestMessage.Headers.Authorization = new AuthenticationHeaderValue(
                        tokenRequest.TokenType,
                        tokenRequest.AccessToken);

                    requestMessage.Headers.Add("Prefer", "outlook.timezone=\"" + TimeZoneInfo.Local.Id + "\"");
                });
            }));

    return graphClient;
}

Then using the client, you can now perform your queries

var graphClient = GetClient();
var user = await graphClient
    .Users["SOME EMAIL ADDRESS HERE"]
    .Request()
    .GetAsync();

Very important: you also have to make sure you have the proper api permissions on your active directory app registration. Without it, you will only get a request denied response from the graph api.

Hope this helps.

like image 2
Jeff Avatar answered Nov 03 '22 11:11

Jeff