microsoft/semantic-kernel · critical · InvalidOperationException

Please provide valid MSGraph configuration in…

Error message

Please provide valid MSGraph configuration in appsettings.Development.json file.

What it means

BearerAuthenticationProviderWithCancellationToken reads MSGraph:ClientId and MSGraph:TenantId from IConfiguration in its constructor and throws InvalidOperationException if either is null/empty. It then builds a PublicClientApplication, so this guard prevents MSAL from being constructed with invalid authority. The message points at appsettings.Development.json specifically because the sample loads development config there.

Solutions

  1. Add an MSGraph section with ClientId and TenantId to appsettings.Development.json.
  2. Confirm ASPNETCORE_ENVIRONMENT (or equivalent) is Development so the file is loaded.
  3. Verify the JSON key names exactly match MSGraph:ClientId / MSGraph:TenantId (case-sensitive path).
  4. As a fallback set the same keys via environment variables (MSGraph__ClientId, MSGraph__TenantId).

Example fix

// before
if (string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(tenantId))
    throw new InvalidOperationException("Please provide valid MSGraph configuration...");

// after (appsettings.Development.json)
{
  "MSGraph": { "ClientId": "<app-id>", "TenantId": "<tenant-id>" }
}
Defensive patterns

Strategy: validation

Validate before calling

var clientId = configuration["MSGraph:ClientId"];
var tenantId = configuration["MSGraph:TenantId"];
if (string.IsNullOrWhiteSpace(clientId) || string.IsNullOrWhiteSpace(tenantId))
    throw new InvalidOperationException(
        "Missing MSGraph:ClientId/TenantId. Add them to appsettings.Development.json or env vars MSGraph__ClientId/MSGraph__TenantId.");

Type guard

static bool HasMsGraphConfig(IConfiguration c) =>
    !string.IsNullOrEmpty(c["MSGraph:ClientId"]) && !string.IsNullOrEmpty(c["MSGraph:TenantId"]);

Prevention

When it happens

Trigger: Constructor invoked with an IConfiguration where configuration["MSGraph:ClientId"] or ["MSGraph:TenantId"] is null or empty string.

Common situations: appsettings.Development.json missing or lacking the MSGraph section, the section present but under a different key (e.g. AzureAd:ClientId), or the Development environment not active so the file isn't loaded.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/596b51af73e879d1. Report an issue: GitHub.

Appendix: source

Thrown at dotnet/samples/Demos/CopilotAgentPlugins/CopilotAgentPluginsDemoSample/BearerAuthenticationProviderWithCancellationToken.cs:27

/// "bearer" authentication scheme.
/// </summary>
public class BearerAuthenticationProviderWithCancellationToken
{
    private readonly IPublicClientApplication _client;

    /// <summary>
    /// Creates an instance of the <see cref="BearerAuthenticationProviderWithCancellationToken"/> class.
    /// </summary>
    /// <param name="configuration">The configuration instance to read settings from.</param>
    public BearerAuthenticationProviderWithCancellationToken(IConfiguration configuration)
    {
        ArgumentNullException.ThrowIfNull(configuration);
        var clientId = configuration["MSGraph:ClientId"];
        var tenantId = configuration["MSGraph:TenantId"];

        if (string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(tenantId))
        {
            throw new InvalidOperationException("Please provide valid MSGraph configuration in appsettings.Development.json file.");
        }

        this._client = PublicClientApplicationBuilder
            .Create(clientId)
            .WithAuthority($"https://login.microsoftonline.com/{tenantId}")
            .WithDefaultRedirectUri()
            .Build();
    }

    /// <summary>
    /// Applies the token to the provided HTTP request message.
    /// </summary>
    /// <param name="request">The HTTP request message.</param>
    /// <param name="cancellationToken"></param>
    public async Task AuthenticateRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken = default)
    {
        var token = await this.GetAccessTokenAsync(cancellationToken).ConfigureAwait(false);
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);

View on GitHub (pinned to c028a0c7dc)