Skip to content

[Bug] WithClientAssertion(ClientSignedAssertion) overload missing null validation for delegate parameter #5955

@gladjohn

Description

@gladjohn

Library version used

latest

.NET version

net 8

Scenario

ConfidentialClient - service to service (AcquireTokenForClient)

Is this a new or an existing app?

This is a new app or experiment

Issue description and reproduction steps

Bug

The WithClientAssertion(Func<AssertionRequestOptions, CancellationToken, Task<ClientSignedAssertion>>) overload in ConfidentialClientApplicationBuilder does not validate the delegate parameter for null, unlike every other WithClientAssertion overload.

Expected Behavior

Passing null should throw ArgumentNullException(nameof(clientSignedAssertionProvider)) at build time, consistent with other overloads.

Actual Behavior

Passing null succeeds at build time. The null delegate is stored and causes a NullReferenceException at runtime when MSAL attempts to invoke it during token acquisition. The XML doc also incorrectly claims MsalClientException is thrown.

Root Cause

The overload at ConfidentialClientApplicationBuilder.cs:333-338 passes the delegate directly to WithClientAssertionInternal without a null guard:

// Current code — no null check
public ConfidentialClientApplicationBuilder WithClientAssertion(Func<AssertionRequestOptions,
    CancellationToken, Task<ClientSignedAssertion>> clientSignedAssertionProvider)
{
    return WithClientAssertionInternal(
        clientSignedAssertionProvider: clientSignedAssertionProvider);
}

All other overloads validate first:

// Other overloads — correct pattern (lines 292, 311)
if (clientAssertionAsyncDelegate == null)
{
    throw new ArgumentNullException(nameof(clientAssertionAsyncDelegate));
}

### Relevant code snippets

```csharp

Expected behavior

Fix

  1. Add null validation to the overload:

public ConfidentialClientApplicationBuilder WithClientAssertion(Func<AssertionRequestOptions,
CancellationToken, Task> clientSignedAssertionProvider)
{
if (clientSignedAssertionProvider == null)
{
throw new ArgumentNullException(nameof(clientSignedAssertionProvider));
}

   return WithClientAssertionInternal(
       clientSignedAssertionProvider: clientSignedAssertionProvider);

}

  1. Update XML doc: change to on line
    332.
  2. Add a unit test verifying ArgumentNullException is thrown.

Files to Change

┌───────────────────────────────────────────────────────────────────────────────────────────┬──────────────────────────────┐
│ File │ Change │
├───────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────┤
│ src/client/Microsoft.Identity.Client/AppConfig/ConfidentialClientApplicationBuilder.cs │ Add null guard + fix XML doc │
├───────────────────────────────────────────────────────────────────────────────────────────┼──────────────────────────────┤
│ tests/Microsoft.Identity.Test.Unit/PublicApiTests/ConfidentialClientApplicationTests.cs │ Add test for null delegate │
└───────────────────────────────────────────────────────────────────────────────────────────┴──────────────────────────────┘

Context

Identity provider

Microsoft Entra ID (Work and School accounts and Personal Microsoft accounts)

Regression

No response

Solution and workarounds

No response

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions