I have written the following code:

<C#>


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Graph;
using Outlook = Microsoft.Office.Interop.Outlook;
using Microsoft.Graph.Models;
using Azure.Identity;
using System.Security.Policy;
using Microsoft.Office.Tools;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ListView;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
using System.Globalization;

namespace Outage_Helper
{
public partial class OutageCalendarPane : UserControl
{
private const string ClientId = “XXXX”;
private const string TenantId = “XXXX”;
private const string UtilityAccountUsername = “<PRESIDIO_ANONYMIZED_EMAIL_ADDRESS>”;
private const string UtilityAccountPassword = “XXXX”;
private GraphServiceClient _graphClient;
private Outlook.MailItem _selectedMailItem;

public OutageCalendarPane(Outlook.MailItem selectedMailItem)
{
InitializeComponent();
_selectedMailItem = selectedMailItem;
emailContentTextBox.Text = selectedMailItem.Body;
AuthenticateAndInitializeGraphClient().ConfigureAwait(false);
}

private async Task AuthenticateAndInitializeGraphClient()
{
var credential = new ClientSecretCredential(TenantId, ClientId, UtilityAccountPassword);
_graphClient = new GraphServiceClient(credential);
}



private async void submitBtn_Click(object sender, EventArgs e)
{
if (_graphClient != null)
{
string calendarId = “XXXX”;
var newEvent = new Event
{
Subject = eventNameTextBox.Text,
Start = new DateTimeTimeZone { DateTime = startDateTimePicker.Value.ToString(“o”), TimeZone = “UTC” },
End = new DateTimeTimeZone { DateTime = endDateTimePicker.Value.ToString(“o”), TimeZone = “UTC” },
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = $“Username: { _selectedMailItem.Sender.Name}\nNote: { eventNoteTextBox.Text}\n\nEmail Text: { emailContentTextBox.Text}”
}
};

await _graphClient.Users[UtilityAccountUsername].Calendars[calendarId].Events.PostAsync(newEvent).ConfigureAwait(false);
MessageBox.Show(“Outage event has been added to the shared calendar.”);
((Form)this.TopLevelControl).Close();
}
else
{
MessageBox.Show(“Error: Unable to add the outage event. Please try again.”);
}
}

private void cancelBtn_Click(object sender, EventArgs e)
{
((Form)this.TopLevelControl).Close();
}
}
}


</C#>

In the above code secret values have been replaced with XXXX.

The private async Task AuthenticateAndInitializeGraphClient() is not working. It appears to not have an await condition, and additionally when run the variable _graphClient is null when it should be a ClientSecretCredential with the TenantID, ClientID and UtilityAccountPassword (app secret). These values are specified correctly in the code.

An example of working authentication code is as follows:

<C#>


using Azure.Core;
using Azure.Identity;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.Graph;

namespace WebMvcGraph5Ofo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class HelloController : ControllerBase
    {
        public async Task<string> Get() {
            StringValues authorizationToken;
            HttpContext.Request.Headers.TryGetValue("Authorization", out authorizationToken);
            var token = authorizationToken.ToString().Replace("Bearer ","");
            var scopes = new[] { "User.Read.All" };
            var tenantId = "tenantId";
            var clientId = "client_id";
            var clientSecret = "client_secret";
            var onBehalfOfCredential = new OnBehalfOfCredential(tenantId, clientId, clientSecret, token);
            var tokenRequestContext = new TokenRequestContext(scopes);
            var token2 = onBehalfOfCredential.GetTokenAsync(tokenRequestContext, new CancellationToken()).Result.Token;
            var graphClient = new GraphServiceClient(onBehalfOfCredential, scopes);
            var user = await graphClient.Users.GetAsync();
            return "hello";
        }

        [Route("ClientCredentialFlow")]
        public async Task<string> clientAsync() {
            var scopes = new[] { "https://graph.microsoft.com/.default" };
            var tenantId = "tenantId";
            var clientId = "client_id";
            var clientSecret = "client_secret";
            var clientSecretCredential = new ClientSecretCredential(
                            tenantId, clientId, clientSecret);
            var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
            var users = await graphClient.Users.GetAsync();
            return "world";
        }
        
        [Route("provider")]
        public async Task<string> providerAsync()
        {
            StringValues authorizationToken;
            HttpContext.Request.Headers.TryGetValue("Authorization", out authorizationToken);
            string incomingToken = authorizationToken.ToString().Replace("Bearer ", "");
            TokenProvider provider = new TokenProvider();
            provider.token = incomingToken;
            var authenticationProvider = new BaseBearerTokenAuthenticationProvider(provider);
            var graphServiceClient = new GraphServiceClient(authenticationProvider);
            var user = await graphServiceClient.Users.GetAsync();
            return "!!";
        }
    }
    
    public class TokenProvider : IAccessTokenProvider
    {
        public string token { get; set; }
        public AllowedHostsValidator AllowedHostsValidator => throw new NotImplementedException();

        public Task<string> GetAuthorizationTokenAsync(Uri uri, Dictionary<string, object>? additionalAuthenticationContext = null, CancellationToken cancellationToken = default)
        {
            return Task.FromResult(token);
        }
    }
}


</C#>

Please help me debug and fix this error. The solution must work with Microsoft.Graph 5.0 or above (ie, cannot use DelegateAuthenticationProvider or other deprecated approaches), however may involve the setting up of logging and breakpoints, etc, to gather more information.