Fix #3894: make Microsoft.Identity.Client.KeyAttestation a conditional (modern .NET only) dependency#3922
Merged
Conversation
…l (modern .NET only) dependency Microsoft.Identity.Web.Certificateless targeted only netstandard2.0 with an unconditional reference to Microsoft.Identity.Client.KeyAttestation, which transitively pulls the native-only Microsoft.Azure.Security.KeyGuardAttestation package. That package ships no .NET Framework/netstandard-compatible managed assets, so classic packages.config .NET Framework projects fail to install Microsoft.Identity.Web 4.11.0+. Multi-target Certificateless (netstandard2.0;net8.0 - net9/net10 consumers resolve the net8 asset) and restrict the KeyAttestation dependency to .NETCoreApp targets, guarding the using and .WithAttestationSupport() calls with #if NETCOREAPP. .NET Framework consumers now use the clean netstandard2.0 asset; modern .NET keeps full mTLS PoP + attestation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
gladjohn
force-pushed
the
gladjohn/fix-3894-conditional-keyattestation
branch
from
July 3, 2026 14:45
8ba10f8 to
a38dc0a
Compare
bgavrilMS
approved these changes
Jul 3, 2026
iarekk
approved these changes
Jul 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #3894.
Microsoft.Identity.Web4.11.0+ cannot be installed into classic (packages.config) .NET Framework projects. Restore fails with:This PR makes the
Microsoft.Identity.Client.KeyAttestationdependency conditional on modern .NET (.NETCoreApp), so .NET Framework consumers no longer drag in the native-only attestation package, while modern .NET keeps full mTLS PoP + key-attestation functionality.Root cause
Microsoft.Identity.Web.Certificatelesstargeted onlynetstandard2.0and referencedMicrosoft.Identity.Client.KeyAttestationunconditionally:netstandard2.0) package exposes one NuGet dependency group that applies to every compatible consumer — including .NET Framework 4.6.2 / 4.7.2 / 4.8.Microsoft.Identity.Client.KeyAttestationtransitively depends onMicrosoft.Azure.Security.KeyGuardAttestation, which is a native (C++) package:<tags>Native native</tags>, no<dependencies>, noframeworkAssembliesbuild/native/**(headers +.lib/.dll) andruntimes/win-x64/native/**lib/assembly and no .NET Framework / netstandard-compatible assetDependency chain on .NET Framework:
Why only some users hit it
packages.config) — ASP.NET "Web Site", MVC Web AppPackageReference)This is why the two reporters (a net48 "website" and a net472 "MVC Web Application", both
packages.config) fail, while SDK-style projects do not.The fix
Key attestation (via KeyGuard) is only available/meaningful on modern .NET Confidential VMs, so the dependency is restricted to
.NETCoreApptargets:Microsoft.Identity.Web.Certificateless.csprojnetstandard2.0;net8.0(wasnetstandard2.0only). This is the minimum needed:net9/net10consumers resolve thenet8asset (which carries attestation), so no additional modern TFMs are required.Microsoft.Identity.Client.KeyAttestationPackageReferenceinto anItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'".ManagedIdentityClientAssertion.cs/TokenAcquisition.csusing Microsoft.Identity.Client.KeyAttestation;and the.WithAttestationSupport()call with#if NETCOREAPP..WithMtlsProofOfPossession()is base MSAL (all TFMs) and is intentionally kept: the mTLS PoP path is unchanged; only the attestation add-on is compiled out on non-.NETCoreApptargets.AzureIdentityForKubernetesClientAssertion.csFile.ReadAllText(_filePath!)— a pre-existing latent null-deref that only surfaced once the project began compiling for net8.0 (whose reference assemblies annotate the parameter as non-null, and the repo builds withTreatWarningsAsErrors). Matches the existing_filePath!usage a few lines below.Design notes
netstandard2.0-only? For.WithAttestationSupport()to actually run on modern .NET it must be compiled into a build whereNETCOREAPPis defined. A netstandard2.0-only project never defines it, so the attestation code would be compiled out for everyone. Multi-targeting is the only NuGet mechanism for a per-consumer-framework-conditional dependency, andManagedIdentityClientAssertionis a public type so it can't be relocated to another project without an API break.Certificate,TokenCache,Diagnostics,TokenAcquisition) already multi-targets;Certificatelesswas the onlynetstandard2.0-only one. The.NETCoreAppconditional-dependency pattern already exists in 5 csprojs.#if NETCOREAPP(not#if NET8_0_OR_GREATER) so the guard exactly mirrors the MSBuild'$(TargetFrameworkIdentifier)' == '.NETCoreApp'condition.PlatformNotSupportedException. Public API (GetSignedAssertionWithBindingAsync,SupportsTokenBinding) is identical across all TFMs; on .NET Framework the binding path simply omits the attestation add-on.netstandard2.0remains the single .NET Framework-facing asset — net462/net472/net48 consumers resolve to it and get a clean graph. No new net462/net472 assets are introduced.Validation (all local)
Package dependency groups (
dotnet pack-> inspect.nuspec):KeyAttestationdependencynet8.0netstandard2.0End-to-end restore matrix (packed all 6 IdWeb packages to a local feed, restored real consumer projects):
Build (0 warnings, 0 errors):
Certificatelessacrossnetstandard2.0;net8.0;TokenAcquisitionand the full dependency chain acrossnet462;net472;netstandard2.0;net8.0;net9.0;net10.0— the latter confirmsnet9/net10consumers correctly bind Certificateless'snet8asset.Unit tests (
Microsoft.Identity.Web.Test, 0 failures):Risk / compatibility
packages.config), so nothing is lost there.Files changed
src/Microsoft.Identity.Web.Certificateless/Microsoft.Identity.Web.Certificateless.csprojsrc/Microsoft.Identity.Web.Certificateless/ManagedIdentityClientAssertion.cssrc/Microsoft.Identity.Web.Certificateless/AzureIdentityForKubernetesClientAssertion.cssrc/Microsoft.Identity.Web.TokenAcquisition/TokenAcquisition.cschangelog.md