diff --git a/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApiExtensions.cs b/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApiExtensions.cs index f05679cd9..ea85ae834 100644 --- a/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApiExtensions.cs +++ b/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApiExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -23,6 +24,10 @@ public static class DownstreamApiExtensions /// This is the name used when calling the service from controller/pages. /// Configuration. /// The builder for chaining. +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] +#endif public static IServiceCollection AddDownstreamApi( this IServiceCollection services, string serviceName, @@ -30,9 +35,16 @@ public static IServiceCollection AddDownstreamApi( { _ = Throws.IfNull(services); +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + // Help the compiler figure out the type so that the code generator generates the binding code + services.AddOptions(serviceName) + .Bind(configuration); +#else // Help the compiler figure out the type so that the code generator generates // the binding code services.Configure(serviceName, configuration); +#endif RegisterDownstreamApi(services); return services; } @@ -65,6 +77,10 @@ public static IServiceCollection AddDownstreamApi( /// This is the name used when calling the service from controller/pages. /// Configuration section. /// The builder for chaining. +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] +#endif public static IServiceCollection AddDownstreamApis( this IServiceCollection services, IConfigurationSection configurationSection) @@ -78,7 +94,13 @@ public static IServiceCollection AddDownstreamApis( foreach (var optionsForService in options.Keys) { +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + services.AddOptions(optionsForService) + .Bind(configurationSection.GetSection(optionsForService)); +#else services.Configure(optionsForService, configurationSection.GetSection(optionsForService)); +#endif } RegisterDownstreamApi(services); return services; diff --git a/src/Microsoft.Identity.Web.GraphServiceClient/GraphServiceCollectionExtensions.cs b/src/Microsoft.Identity.Web.GraphServiceClient/GraphServiceCollectionExtensions.cs index eb22c3149..cadce8f6a 100644 --- a/src/Microsoft.Identity.Web.GraphServiceClient/GraphServiceCollectionExtensions.cs +++ b/src/Microsoft.Identity.Web.GraphServiceClient/GraphServiceCollectionExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net.Http; using Microsoft.Extensions.Configuration; @@ -40,9 +41,20 @@ public static IServiceCollection AddMicrosoftGraph(this IServiceCollection servi /// Builder. /// Configuration section containing the Microsoft graph config. /// The service collection to chain. +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] +#endif public static IServiceCollection AddMicrosoftGraph(this IServiceCollection services, IConfiguration configurationSection) { +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + services.AddOptions() + .Bind(configurationSection); + return services.AddMicrosoftGraph(_ => { }); // No-op, binding already done +#else return services.AddMicrosoftGraph(o => configurationSection.Bind(o)); +#endif } /// diff --git a/src/Microsoft.Identity.Web.GraphServiceClientBeta/GraphBetaServiceCollectionExtensions.cs b/src/Microsoft.Identity.Web.GraphServiceClientBeta/GraphBetaServiceCollectionExtensions.cs index 0a5abcdbd..5615f5987 100644 --- a/src/Microsoft.Identity.Web.GraphServiceClientBeta/GraphBetaServiceCollectionExtensions.cs +++ b/src/Microsoft.Identity.Web.GraphServiceClientBeta/GraphBetaServiceCollectionExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Net.Http; using Microsoft.Extensions.Configuration; @@ -40,9 +41,20 @@ public static IServiceCollection AddMicrosoftGraphBeta(this IServiceCollection s /// Builder. /// Configuration section containing the Microsoft graph config. /// The service collection to chain. +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] +#endif public static IServiceCollection AddMicrosoftGraphBeta(this IServiceCollection services, IConfiguration configurationSection) { +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + services.AddOptions() + .Bind(configurationSection); + return services.AddMicrosoftGraphBeta(_ => { }); // No-op, binding already done +#else return services.AddMicrosoftGraphBeta(o => configurationSection.Bind(o)); +#endif } /// diff --git a/src/Microsoft.Identity.Web.MicrosoftGraph/MicrosoftGraphExtensions.cs b/src/Microsoft.Identity.Web.MicrosoftGraph/MicrosoftGraphExtensions.cs index 4c90b0fcb..62d9f0200 100644 --- a/src/Microsoft.Identity.Web.MicrosoftGraph/MicrosoftGraphExtensions.cs +++ b/src/Microsoft.Identity.Web.MicrosoftGraph/MicrosoftGraphExtensions.cs @@ -27,13 +27,24 @@ public static class MicrosoftGraphExtensions /// The builder to chain. #if NET6_0_OR_GREATER && !NET8_0_OR_GREATER [RequiresUnreferencedCode("Microsoft.Extensions.Configuration.ConfigurationBinder.Bind(IConfiguration, Object).")] +#endif +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] #endif public static MicrosoftIdentityAppCallsWebApiAuthenticationBuilder AddMicrosoftGraph( this MicrosoftIdentityAppCallsWebApiAuthenticationBuilder builder, IConfigurationSection configurationSection) { +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + builder.Services.AddOptions() + .Bind(configurationSection); + return builder.AddMicrosoftGraph(_ => { }); // No-op, binding already done +#else return builder.AddMicrosoftGraph( options => configurationSection.Bind(options)); +#endif } /// diff --git a/src/Microsoft.Identity.Web.TokenAcquisition/MicrosoftIdentityBaseAuthenticationBuilder.cs b/src/Microsoft.Identity.Web.TokenAcquisition/MicrosoftIdentityBaseAuthenticationBuilder.cs index 306808905..a1d72eef3 100644 --- a/src/Microsoft.Identity.Web.TokenAcquisition/MicrosoftIdentityBaseAuthenticationBuilder.cs +++ b/src/Microsoft.Identity.Web.TokenAcquisition/MicrosoftIdentityBaseAuthenticationBuilder.cs @@ -25,6 +25,10 @@ public class MicrosoftIdentityBaseAuthenticationBuilder /// Optional configuration section. #if NET6_0_OR_GREATER && !NET8_0_OR_GREATER [RequiresUnreferencedCode("Calls Microsoft.Extensions.Configuration.ConfigurationBinder.Bind(IConfiguration, Object).")] +#endif +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "LoggingOptions is a simple POCO compatible with source generators")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "LoggingOptions is a simple POCO compatible with source generators")] #endif protected MicrosoftIdentityBaseAuthenticationBuilder( IServiceCollection services, @@ -38,6 +42,9 @@ protected MicrosoftIdentityBaseAuthenticationBuilder( IdentityModelEventSource.ShowPII = logOptions.EnablePiiLogging; } +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "GetValue for primitive types is AOT-safe")] +#endif internal static void SetIdentityModelLogger(IServiceProvider serviceProvider) { if (serviceProvider != null) diff --git a/src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquirerFactory.cs b/src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquirerFactory.cs index 3e476e7ed..3091d4ad5 100644 --- a/src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquirerFactory.cs +++ b/src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquirerFactory.cs @@ -80,6 +80,10 @@ protected TokenAcquirerFactory() /// #if NET6_0_OR_GREATER && !NET8_0_OR_GREATER [RequiresUnreferencedCode("Calls Microsoft.Extensions.Configuration.ConfigurationBinder.Bind(IConfiguration, Object).")] +#endif +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] #endif static public T GetDefaultInstance(string configSection="AzureAd") where T : TokenAcquirerFactory, new() { @@ -95,6 +99,17 @@ protected TokenAcquirerFactory() defaultInstance = instance; instance.Services.AddTokenAcquisition(); instance.Services.AddHttpClient(); +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + var configSection2 = instance.Configuration.GetSection(configSection); + instance.Services.AddOptions() + .Bind(configSection2); + instance.Services.Configure(option => + { + // This is temporary and will be removed eventually. + CiamAuthorityHelper.BuildCiamAuthorityIfNeeded(option); + }); +#else instance.Services.Configure(option => { instance.Configuration.GetSection(configSection).Bind(option); @@ -102,6 +117,7 @@ protected TokenAcquirerFactory() // This is temporary and will be removed eventually. CiamAuthorityHelper.BuildCiamAuthorityIfNeeded(option); }); +#endif instance.Services.AddSingleton(); instance.Services.AddSingleton(defaultInstance.Configuration); } @@ -123,6 +139,10 @@ protected TokenAcquirerFactory() /// #if NET6_0_OR_GREATER && !NET8_0_OR_GREATER [RequiresUnreferencedCode("Calls Microsoft.Extensions.Configuration.ConfigurationBinder.Bind(IConfiguration, Object).")] +#endif +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] #endif static public TokenAcquirerFactory GetDefaultInstance(string configSection = "AzureAd") { @@ -138,6 +158,17 @@ static public TokenAcquirerFactory GetDefaultInstance(string configSection = "Az defaultInstance = instance; instance.Services.AddTokenAcquisition(); instance.Services.AddHttpClient(); +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + var configSection2 = instance.Configuration.GetSection(configSection); + instance.Services.AddOptions() + .Bind(configSection2); + instance.Services.Configure(option => + { + // This is temporary and will be removed eventually. + CiamAuthorityHelper.BuildCiamAuthorityIfNeeded(option); + }); +#else instance.Services.Configure(option => { instance.Configuration.GetSection(configSection).Bind(option); @@ -145,6 +176,7 @@ static public TokenAcquirerFactory GetDefaultInstance(string configSection = "Az // This is temporary and will be removed eventually. CiamAuthorityHelper.BuildCiamAuthorityIfNeeded(option); }); +#endif instance.Services.AddSingleton(); instance.Services.AddSingleton(defaultInstance.Configuration); } diff --git a/src/Microsoft.Identity.Web.TokenAcquisition/WebApiBuilders.cs b/src/Microsoft.Identity.Web.TokenAcquisition/WebApiBuilders.cs index 152970ddc..8a770900f 100644 --- a/src/Microsoft.Identity.Web.TokenAcquisition/WebApiBuilders.cs +++ b/src/Microsoft.Identity.Web.TokenAcquisition/WebApiBuilders.cs @@ -28,6 +28,10 @@ public static class WebApiBuilders /// The authentication builder to chain. #if NET6_0_OR_GREATER && !NET8_0_OR_GREATER [RequiresUnreferencedCode("Calls Bind, Configure with Unspecified Configuration and ServiceCollection.")] +#endif +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] #endif public static MicrosoftIdentityAppCallsWebApiAuthenticationBuilder EnableTokenAcquisition( Action configureConfidentialClientApplicationOptions, @@ -37,6 +41,13 @@ public static MicrosoftIdentityAppCallsWebApiAuthenticationBuilder EnableTokenAc { if (configuration != null) { +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + services.AddOptions(authenticationScheme) + .Bind(configuration); + services.AddOptions(authenticationScheme) + .Bind(configuration); +#else // TODO: This never was right. And the configureConfidentialClientApplicationOptions delegate is not used // services.Configure(authenticationScheme, configuration); services.Configure(authenticationScheme, options @@ -45,6 +56,7 @@ public static MicrosoftIdentityAppCallsWebApiAuthenticationBuilder EnableTokenAc services.Configure(authenticationScheme, options => { configuration.Bind(options); }); +#endif } services.AddTokenAcquisition(); diff --git a/src/Microsoft.Identity.Web/DownstreamWebApiSupport/DownstreamWebApiExtensions.cs b/src/Microsoft.Identity.Web/DownstreamWebApiSupport/DownstreamWebApiExtensions.cs index 3d21f4930..bee6c593e 100644 --- a/src/Microsoft.Identity.Web/DownstreamWebApiSupport/DownstreamWebApiExtensions.cs +++ b/src/Microsoft.Identity.Web/DownstreamWebApiSupport/DownstreamWebApiExtensions.cs @@ -27,6 +27,10 @@ public static class DownstreamWebApiExtensions [EditorBrowsable(EditorBrowsableState.Never)] #if NET6_0_OR_GREATER && !NET8_0_OR_GREATER [RequiresUnreferencedCode("Calls Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure(IServiceCollection, String, IConfiguration).")] +#endif +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] #endif public static MicrosoftIdentityAppCallsWebApiAuthenticationBuilder AddDownstreamWebApi( this MicrosoftIdentityAppCallsWebApiAuthenticationBuilder builder, @@ -35,7 +39,13 @@ public static MicrosoftIdentityAppCallsWebApiAuthenticationBuilder AddDownstream { _ = Throws.IfNull(builder); +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + builder.Services.AddOptions(serviceName) + .Bind(configuration); +#else builder.Services.Configure(serviceName, configuration); +#endif builder.Services.AddHttpClient(); return builder; } diff --git a/src/Microsoft.Identity.Web/DownstreamWebApiSupport/MicrosoftIdentityAuthenticationMessageHandlerHttpClientBuilderExtensions.cs b/src/Microsoft.Identity.Web/DownstreamWebApiSupport/MicrosoftIdentityAuthenticationMessageHandlerHttpClientBuilderExtensions.cs index 94f3cb794..837566480 100644 --- a/src/Microsoft.Identity.Web/DownstreamWebApiSupport/MicrosoftIdentityAuthenticationMessageHandlerHttpClientBuilderExtensions.cs +++ b/src/Microsoft.Identity.Web/DownstreamWebApiSupport/MicrosoftIdentityAuthenticationMessageHandlerHttpClientBuilderExtensions.cs @@ -24,6 +24,10 @@ public static class MicrosoftIdentityAuthenticationMessageHandlerHttpClientBuild /// The builder for chaining. #if NET6_0_OR_GREATER && !NET8_0_OR_GREATER [RequiresUnreferencedCode("Calls Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure(IServiceCollection, String, IConfiguration).")] +#endif +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] #endif public static IHttpClientBuilder AddMicrosoftIdentityUserAuthenticationHandler( this IHttpClientBuilder builder, @@ -32,7 +36,13 @@ public static IHttpClientBuilder AddMicrosoftIdentityUserAuthenticationHandler( { _ = Throws.IfNull(builder); +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + builder.Services.AddOptions(serviceName) + .Bind(configuration); +#else builder.Services.Configure(serviceName, configuration); +#endif builder.AddMicrosoftIdentityAuthenticationHandlerCore(factory => factory.CreateUserHandler(serviceName)); return builder; @@ -67,6 +77,10 @@ public static IHttpClientBuilder AddMicrosoftIdentityUserAuthenticationHandler( /// The builder for chaining. #if NET6_0_OR_GREATER && !NET8_0_OR_GREATER [RequiresUnreferencedCode("Calls Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure(IServiceCollection, String, IConfiguration).")] +#endif +#if NET8_0_OR_GREATER + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "Configuration binding with AddOptions().Bind() uses source generators on .NET 8+")] #endif public static IHttpClientBuilder AddMicrosoftIdentityAppAuthenticationHandler( this IHttpClientBuilder builder, @@ -75,7 +89,13 @@ public static IHttpClientBuilder AddMicrosoftIdentityAppAuthenticationHandler( { _ = Throws.IfNull(builder); +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + builder.Services.AddOptions(serviceName) + .Bind(configuration); +#else builder.Services.Configure(serviceName, configuration); +#endif builder.AddMicrosoftIdentityAuthenticationHandlerCore(factory => factory.CreateAppHandler(serviceName)); return builder; diff --git a/src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderExtensions.cs b/src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderExtensions.cs index 2d7b92c00..64563cad5 100644 --- a/src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderExtensions.cs +++ b/src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderExtensions.cs @@ -81,6 +81,27 @@ public static MicrosoftIdentityWebApiAuthenticationBuilderWithConfiguration AddM _ = Throws.IfNull(configurationSection); _ = Throws.IfNull(builder); +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + AddMicrosoftIdentityWebApiImplementation( + builder, + _ => { }, // No-op - binding handled below via AddOptions + jwtBearerScheme, + subscribeToJwtBearerMiddlewareDiagnosticsEvents); + + // Use source generator-based binding for JwtBearerOptions and MicrosoftIdentityOptions + builder.Services.AddOptions(jwtBearerScheme) + .Bind(configurationSection); + builder.Services.AddOptions(jwtBearerScheme) + .Bind(configurationSection); + + return new MicrosoftIdentityWebApiAuthenticationBuilderWithConfiguration( + builder.Services, + jwtBearerScheme, + _ => { }, // No-op - binding handled via AddOptions + _ => { }, // No-op - binding handled via AddOptions + configurationSection); +#else AddMicrosoftIdentityWebApiImplementation( builder, options => configurationSection.Bind(options), @@ -93,6 +114,7 @@ public static MicrosoftIdentityWebApiAuthenticationBuilderWithConfiguration AddM options => configurationSection.Bind(options), options => configurationSection.Bind(options), configurationSection); +#endif } /// diff --git a/src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderWithConfiguration.cs b/src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderWithConfiguration.cs index 1800bc844..33ace88c5 100644 --- a/src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderWithConfiguration.cs +++ b/src/Microsoft.Identity.Web/WebApiExtensions/MicrosoftIdentityWebApiAuthenticationBuilderWithConfiguration.cs @@ -38,7 +38,12 @@ internal MicrosoftIdentityWebApiAuthenticationBuilderWithConfiguration( #endif public MicrosoftIdentityAppCallsWebApiAuthenticationBuilder EnableTokenAcquisitionToCallDownstreamApi() { +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding + return EnableTokenAcquisitionToCallDownstreamApi(_ => { }); // No-op, binding handled via AddOptions +#else return EnableTokenAcquisitionToCallDownstreamApi(options => ConfigurationSection?.Bind(options)); +#endif } } } diff --git a/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderExtensions.cs b/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderExtensions.cs index 1e731d0c0..821b8c5ec 100644 --- a/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderExtensions.cs +++ b/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderExtensions.cs @@ -94,6 +94,27 @@ public static MicrosoftIdentityWebAppAuthenticationBuilderWithConfiguration AddM _ = Throws.IfNull(builder); _ = Throws.IfNull(configurationSection); +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + AddMicrosoftIdentityWebAppInternal( + builder, + _ => { }, // No-op - binding handled below via AddOptions + null, + openIdConnectScheme, + cookieScheme, + subscribeToOpenIdConnectMiddlewareDiagnosticsEvents, + displayName); + + // Use source generator-based binding + builder.Services.AddOptions(openIdConnectScheme) + .Bind(configurationSection); + + return new MicrosoftIdentityWebAppAuthenticationBuilderWithConfiguration( + builder.Services, + openIdConnectScheme, + _ => { }, // No-op - binding handled via AddOptions + configurationSection); +#else return builder.AddMicrosoftIdentityWebAppWithConfiguration( options => configurationSection.Bind(options), null, @@ -102,6 +123,7 @@ public static MicrosoftIdentityWebAppAuthenticationBuilderWithConfiguration AddM subscribeToOpenIdConnectMiddlewareDiagnosticsEvents, displayName, configurationSection); +#endif } /// diff --git a/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderWithConfiguration.cs b/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderWithConfiguration.cs index df58161bc..7a72303d9 100644 --- a/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderWithConfiguration.cs +++ b/src/Microsoft.Identity.Web/WebAppExtensions/MicrosoftIdentityWebAppAuthenticationBuilderWithConfiguration.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Identity.Client; namespace Microsoft.Identity.Web { @@ -49,6 +50,26 @@ internal MicrosoftIdentityWebAppAuthenticationBuilderWithConfiguration( { Services.AddHttpClient(); +#if NET8_0_OR_GREATER + // For .NET 8+, use source generator-based binding for AOT compatibility + if (ConfigurationSection != null) + { + Services.AddOptions() + .Bind(ConfigurationSection); + } + + return EnableTokenAcquisitionToCallDownstreamApi( + options => + { + if (AppServicesAuthenticationInformation.IsAppServicesAadAuthenticationEnabled) + { + options.ClientId = AppServicesAuthenticationInformation.ClientId; + options.ClientSecret = AppServicesAuthenticationInformation.ClientSecret; + options.Instance = AppServicesAuthenticationInformation.Issuer; + } + }, + initialScopes); +#else return EnableTokenAcquisitionToCallDownstreamApi( options => { @@ -61,6 +82,7 @@ internal MicrosoftIdentityWebAppAuthenticationBuilderWithConfiguration( } }, initialScopes); +#endif } } }