diff --git a/src/Microsoft.Identity.Web.OWIN/ApiControllerExtensions.cs b/src/Microsoft.Identity.Web.OWIN/ApiControllerExtensions.cs
index d29024777..fa5dd9d53 100644
--- a/src/Microsoft.Identity.Web.OWIN/ApiControllerExtensions.cs
+++ b/src/Microsoft.Identity.Web.OWIN/ApiControllerExtensions.cs
@@ -42,6 +42,20 @@ public static IAuthorizationHeaderProvider GetAuthorizationHeaderProvider(this A
return headerProvider;
}
+ ///
+ /// Get the authorization header provider, exposing the richer surface.
+ ///
+ ///
+ public static IAuthorizationHeaderProvider2 GetAuthorizationHeaderProvider2(this ApiController _)
+ {
+ IAuthorizationHeaderProvider2? headerProvider = TokenAcquirerFactory.GetDefaultInstance().ServiceProvider?.GetService(typeof(IAuthorizationHeaderProvider2)) as IAuthorizationHeaderProvider2;
+ if (headerProvider == null)
+ {
+ throw new ConfigurationErrorsException("Cannot find IAuthorizationHeaderProvider2. Did you create an OwinTokenAcquirerFactory in Startup_Auth.cs?. See https://aka.ms/ms-id-web/owin. ");
+ }
+ return headerProvider;
+ }
+
///
/// Get the downstream API service from an ApiController.
///
diff --git a/src/Microsoft.Identity.Web.OWIN/ControllerBaseExtensions.cs b/src/Microsoft.Identity.Web.OWIN/ControllerBaseExtensions.cs
index f56727505..3a2940422 100644
--- a/src/Microsoft.Identity.Web.OWIN/ControllerBaseExtensions.cs
+++ b/src/Microsoft.Identity.Web.OWIN/ControllerBaseExtensions.cs
@@ -42,6 +42,20 @@ public static IAuthorizationHeaderProvider GetAuthorizationHeaderProvider(this C
return headerProvider;
}
+ ///
+ /// Get the authorization header provider, exposing the richer surface.
+ ///
+ ///
+ public static IAuthorizationHeaderProvider2 GetAuthorizationHeaderProvider2(this ControllerBase _)
+ {
+ IAuthorizationHeaderProvider2? headerProvider = TokenAcquirerFactory.GetDefaultInstance().ServiceProvider?.GetService(typeof(IAuthorizationHeaderProvider2)) as IAuthorizationHeaderProvider2;
+ if (headerProvider == null)
+ {
+ throw new ConfigurationErrorsException("Cannot find IAuthorizationHeaderProvider2. Did you create an OwinTokenAcquirerFactory in Startup_Auth.cs?. See https://aka.ms/ms-id-web/owin. ");
+ }
+ return headerProvider;
+ }
+
///
/// Get the downstream API service from an ApiController.
///
diff --git a/src/Microsoft.Identity.Web.OWIN/PublicAPI/PublicAPI.Unshipped.txt b/src/Microsoft.Identity.Web.OWIN/PublicAPI/PublicAPI.Unshipped.txt
index 7dc5c5811..52a4524b7 100644
--- a/src/Microsoft.Identity.Web.OWIN/PublicAPI/PublicAPI.Unshipped.txt
+++ b/src/Microsoft.Identity.Web.OWIN/PublicAPI/PublicAPI.Unshipped.txt
@@ -1 +1,3 @@
#nullable enable
+static Microsoft.Identity.Web.ApiControllerExtensions.GetAuthorizationHeaderProvider2(this System.Web.Http.ApiController! _) -> Microsoft.Identity.Abstractions.IAuthorizationHeaderProvider2!
+static Microsoft.Identity.Web.ControllerBaseExtensions.GetAuthorizationHeaderProvider2(this System.Web.Mvc.ControllerBase! _) -> Microsoft.Identity.Abstractions.IAuthorizationHeaderProvider2!
diff --git a/src/Microsoft.Identity.Web.TokenAcquisition/ServiceCollectionExtensions.cs b/src/Microsoft.Identity.Web.TokenAcquisition/ServiceCollectionExtensions.cs
index 4fd3ff838..dcdd6f9bb 100644
--- a/src/Microsoft.Identity.Web.TokenAcquisition/ServiceCollectionExtensions.cs
+++ b/src/Microsoft.Identity.Web.TokenAcquisition/ServiceCollectionExtensions.cs
@@ -75,6 +75,7 @@ public static IServiceCollection AddTokenAcquisition(
ServiceDescriptor? ccaProviderService = services.FirstOrDefault(s => s.ServiceType == typeof(IConfidentialClientApplicationProvider));
ServiceDescriptor? tokenAcquisitionhost = services.FirstOrDefault(s => s.ServiceType == typeof(ITokenAcquisitionHost));
ServiceDescriptor? authenticationHeaderCreator = services.FirstOrDefault(s => s.ServiceType == typeof(IAuthorizationHeaderProvider));
+ ServiceDescriptor? authenticationHeaderCreator2 = services.FirstOrDefault(s => s.ServiceType == typeof(IAuthorizationHeaderProvider2));
ServiceDescriptor? tokenAcquirerFactory = services.FirstOrDefault(s => s.ServiceType == typeof(ITokenAcquirerFactory));
ServiceDescriptor? authSchemeInfoProvider = services.FirstOrDefault(s => s.ServiceType == typeof(Abstractions.IAuthenticationSchemeInformationProvider));
ServiceDescriptor? credentialsProviderService = services.FirstOrDefault(s => s.ServiceType == typeof(ICredentialsProvider));
@@ -91,6 +92,11 @@ public static IServiceCollection AddTokenAcquisition(
services.Remove(authenticationHeaderCreator);
services.Remove(authSchemeInfoProvider);
+ if (authenticationHeaderCreator2 != null)
+ {
+ services.Remove(authenticationHeaderCreator2);
+ }
+
if (ccaProviderService != null)
{
services.Remove(ccaProviderService);
@@ -148,6 +154,8 @@ public static IServiceCollection AddTokenAcquisition(
services.AddSingleton(sp =>
sp.GetRequiredService());
services.AddSingleton();
+ // Expose the same instance as IAuthorizationHeaderProvider2 so it can be resolved directly.
+ services.AddSingleton(s => (IAuthorizationHeaderProvider2)s.GetRequiredService());
if (!HasImplementationType(services, typeof(CredentialsProvider)))
{
services.TryAddSingleton();
@@ -183,6 +191,8 @@ public static IServiceCollection AddTokenAcquisition(
services.AddScoped(sp =>
sp.GetRequiredService());
services.AddScoped();
+ // Expose the same instance as IAuthorizationHeaderProvider2 so it can be resolved directly.
+ services.AddScoped(s => (IAuthorizationHeaderProvider2)s.GetRequiredService());
if (!HasImplementationType(services, typeof(CredentialsProvider)))
{
services.TryAddScoped();
diff --git a/tests/Microsoft.Identity.Web.Test/ServiceCollectionExtensionsTests.cs b/tests/Microsoft.Identity.Web.Test/ServiceCollectionExtensionsTests.cs
index 4f4b844af..dce7f6c56 100644
--- a/tests/Microsoft.Identity.Web.Test/ServiceCollectionExtensionsTests.cs
+++ b/tests/Microsoft.Identity.Web.Test/ServiceCollectionExtensionsTests.cs
@@ -74,6 +74,14 @@ public void AddTokenAcquisition_Sdk_AddsWithCorrectLifetime()
Assert.Null(actual.ImplementationFactory);
},
actual =>
+ {
+ Assert.Equal(ServiceLifetime.Scoped, actual.Lifetime);
+ Assert.Equal(typeof(IAuthorizationHeaderProvider2), actual.ServiceType);
+ Assert.Null(actual.ImplementationType);
+ Assert.Null(actual.ImplementationInstance);
+ Assert.NotNull(actual.ImplementationFactory);
+ },
+ actual =>
{
Assert.Equal(typeof(ICredentialsLoader), actual.ServiceType);
Assert.Equal(typeof(DefaultCertificateLoader), actual.ImplementationType);
@@ -155,7 +163,7 @@ public void AddTokenAcquisition_Sdk_SupportsKeyedServices()
services.AddTokenAcquisition();
// Verify the number of services added by AddTokenAcquisition (ignoring the service we added here).
- Assert.Equal(14, services.Count(t => t.ServiceType != typeof(ServiceCollectionExtensionsTests)));
+ Assert.Equal(15, services.Count(t => t.ServiceType != typeof(ServiceCollectionExtensionsTests)));
}
#endif
@@ -210,6 +218,43 @@ public void AddTokenAcquisition_ResolvesIConfidentialClientApplicationProviderTo
Assert.IsAssignableFrom(confidentialClientApplicationProvider);
}
+ [Fact]
+ public void AddTokenAcquisition_RegistersIAuthorizationHeaderProvider2()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+
+ // Act
+ services.AddTokenAcquisition();
+
+ // Assert
+ ServiceDescriptor serviceDescriptor = Assert.Single(services, s => s.ServiceType == typeof(IAuthorizationHeaderProvider2));
+ Assert.Equal(ServiceLifetime.Scoped, serviceDescriptor.Lifetime);
+ Assert.Null(serviceDescriptor.ImplementationType);
+ Assert.Null(serviceDescriptor.ImplementationInstance);
+ Assert.NotNull(serviceDescriptor.ImplementationFactory);
+ }
+
+ [Fact]
+ public void AddTokenAcquisition_ResolvesIAuthorizationHeaderProvider2ToSameInstanceAsV1()
+ {
+ // Arrange
+ var services = new ServiceCollection();
+ services.AddTokenAcquisition();
+ services.AddInMemoryTokenCaches();
+ services.AddHttpClient();
+ using ServiceProvider serviceProvider = services.BuildServiceProvider();
+ using IServiceScope serviceScope = serviceProvider.CreateScope();
+
+ // Act
+ var headerProvider = serviceScope.ServiceProvider.GetRequiredService();
+ var headerProvider2 = serviceScope.ServiceProvider.GetRequiredService();
+
+ // Assert
+ Assert.Same(headerProvider, headerProvider2);
+ Assert.IsType(headerProvider2);
+ }
+
[Fact]
public void AddHttpContextAccessor_ThrowsWithoutServices()
{
@@ -277,6 +322,14 @@ public void AddTokenAcquisitionCalledTwice_RegistersTokenAcquisitionOnlyAsSingle
Assert.Null(actual.ImplementationFactory);
},
actual =>
+ {
+ Assert.Equal(ServiceLifetime.Singleton, actual.Lifetime);
+ Assert.Equal(typeof(IAuthorizationHeaderProvider2), actual.ServiceType);
+ Assert.Null(actual.ImplementationType);
+ Assert.Null(actual.ImplementationInstance);
+ Assert.NotNull(actual.ImplementationFactory);
+ },
+ actual =>
{
Assert.Equal(typeof(ICredentialsLoader), actual.ServiceType);
Assert.Equal(typeof(DefaultCertificateLoader), actual.ImplementationType);