Search code examples
c#microsoft-graph-apiasp.net-core-webapitoken

Microsoft.Graph C#: Make an API request programmatically


I'm working with Microsoft.Graph SDK and I need to get email SentItems programmatically in a class library.

I'm using the following code to create a client:

private static Graph.GraphServiceClient CreateClient()
{
    var scopes = new[] { "User.Read" };

    // Multi-tenant apps can use "common",
    // single-tenant apps must use the tenant ID from the Azure portal
    var tenantId = "xxx";

    // Value from app registration
    var clientId = "xxxx";

    var pca = Microsoft.Identity.Client.PublicClientApplicationBuilder
        .Create(clientId)
        .WithTenantId(tenantId)
        .Build();

    // DelegateAuthenticationProvider is a simple auth provider implementation
    // that allows you to define an async function to retrieve a token
    // Alternatively, you can create a class that implements IAuthenticationProvider
    // for more complex scenarios
    var authProvider = new Graph.DelegateAuthenticationProvider(async (request) =>
    {
        // Use Microsoft.Identity.Client to retrieve token
        var result = await pca.AcquireTokenByIntegratedWindowsAuth(scopes).ExecuteAsync();

        request.Headers.Authorization =
            new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
    });

    return new Graph.GraphServiceClient(authProvider);
}

then I'm trying to use the client the next waay:

var sentEmails = graphClient.Users[authMail].MailFolders.SentItems.Request().GetAsync().Result;

but I'm getting the following exception when executing the request:

Exception thrown: 'Microsoft.Identity.Client.MsalUiRequiredException' in System.Private.CoreLib.dll Exception thrown: 'System.AggregateException' in System.Private.CoreLib.dll

I thought that another option could be to get an auth token. I can get an auth token with the next code:

private static async Task<string> GetGraphToken()
{
    var resource = "https://graph.microsoft.com/";
    var instance = "https://login.microsoftonline.com/";
    var tenant = "xxx";
    var clientID = "xxxx";
    var secret = "xxxxx";
    var authority = $"{instance}{tenant}";
    var authContext = new AuthenticationContext(authority);
    var credentials = new ClientCredential(clientID, secret);
    var authResult = authContext.AcquireTokenAsync(resource, credentials).Result;
    return authResult.AccessToken;
}

And it just works, but then I don't know how to use it to do an API request programmatically.

Any of the two variants is OK for me, getting rid of the exceptions in the first case, or finding a way to use the token to make a programmatic SDK API call in the second.

What can I try next?

Edit 1

I'm trying with the next approach, but the same exception is thrown:

var accessToken = GetToken();

var client = new Graph.GraphServiceClient(
    new Graph.DelegateAuthenticationProvider(
        (requestMessage) =>
        {
            requestMessage.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
            return Task.FromResult(0);
        }));
        
var mails = client.Users[authMail].MailFolders.SentItems.Messages.Request().GetAsync().Result;

Solution

  • In your first example you trying to use IWA auth https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-desktop-acquire-token-integrated-windows-authentication?tabs=dotnet and it failing because there is interaction required. Most likely this is due to MFA being enabled on the account, generally you don't want to disable MFA so you either need to deal with the interaction and perform the other factor or use another method. You also don't have the correct scope for email eg Mail.Read would be required for

    In the second method your using client credentials flow (but the older v1 flow) but if you want to use the Graph SDK it easier to just do https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS#client-credentials-provider but make sure you have the correct permission in your app registration and make sure its been consented to.