microsoft-identity-web: [Bug] Microsoft.Identity.Web.MergedOptions.PrepareAuthorityInstanceForMsal() throws a null reference exception
Which version of Microsoft Identity Web are you using? Note that to get help, you need to run the latest version.
Version is 1.22.3
Where is the issue?
- Web app
- Sign-in users
- Sign-in users and call web APIs
- Web API
- Protected web APIs (validating tokens)
- Protected web APIs (validating scopes)
- Protected web APIs call downstream web APIs
- Token cache serialization
- In-memory caches
- Session caches
- Distributed caches
- Other (please describe)
Is this a new or an existing app?
This is a new app Repro I have the exact same problem as in #1507 . There’s the setup code:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(
openIdConnectScheme: OpenIdConnectDefaults.AuthenticationScheme,
displayName: "Azure AD B2C",
configureMicrosoftIdentityOptions: options =>
ConfigureMicrosoftIdentityOptions(
options,
shellSettings),
configureCookieAuthenticationOptions: ConfigureCookieAuthenticationOptions,
cookieScheme: null,
subscribeToOpenIdConnectMiddlewareDiagnosticsEvents: env.IsDevelopment())
.EnableTokenAcquisitionToCallDownstreamApi()
.AddDownstreamWebApi(AuthenticationConstants.IdentityApiName,
options => { Configuration.GetSection("Portal:Authentication:Api").Bind(options); })
.AddDistributedTokenCaches();
ConfigureMicrosoftIdentityOptions
is defined below:
protected virtual void ConfigureMicrosoftIdentityOptions(
MicrosoftIdentityOptions options,
ShellSettings shellSettings)
{
Configuration.GetSection(PortalAuthenticationConfigSection).Bind(options);
var signInPolicies = Configuration.GetSection(PortalAuthenticationConfigSection).Get<SignInPolicyOptions>();
options.SignUpSignInPolicyId = GetSignInPolicy(signInPolicies);
var urlPrefix = !string.IsNullOrEmpty(shellSettings.RequestUrlPrefix)
? shellSettings.RequestUrlPrefix.Trim('/').PadLeft(1, '/')
: null;
options.CallbackPath = $"{urlPrefix}/{AuthenticationConstants.CallbackPaths.CallbackPath}";
options.SignedOutCallbackPath = $"{urlPrefix}/{AuthenticationConstants.CallbackPaths.SignedOutCallbackPath}";
options.SignedOutRedirectUri = $"{urlPrefix}/{AuthenticationConstants.CallbackPaths.SignedOutPath}";
options.RemoteSignOutPath = $"{urlPrefix}/{AuthenticationConstants.CallbackPaths.RemoteSignOutPath}";
options.ErrorPath = $"{urlPrefix}/{AuthenticationConstants.CallbackPaths.ErrorPath}";
options.ResetPasswordPath = $"{urlPrefix}/{AuthenticationConstants.CallbackPaths.ResetPasswordPath}";
options.AccessDeniedPath = $"{urlPrefix}/{AuthenticationConstants.CallbackPaths.AccessDeniedPath}";
options.GetClaimsFromUserInfoEndpoint = true;
//options.SaveTokens = true;
options.SignInScheme = IdentityConstants.ExternalScheme;
//options.ForwardDefault = IdentityConstants.ExternalScheme;
options.TokenValidationParameters = new()
{
NameClaimType = "name"
};
}
I then inject an instance of IDownstreamWebApi into a controller and call it as follows:
var organizations = await _api.CallWebApiForUserAsync<OrganizationSummary[]>(AuthenticationConstants.IdentityApiName,
api =>
{
api.RelativePath = "organizations/oauth2";
api.HttpMethod = HttpMethod.Get;
});
I can sign in fine using the above code, so authentication works ok. It’s when I need to call the downstream api that I run into issues Expected behavior A clear and concise description of what you expected to happen (or code). I should be able to call the downstream API without errors Actual behavior IDownsteamWebApi.CallWebApiForUserAsync throws NullReferenceException with the following stack trace:
at Microsoft.Identity.Web.MergedOptions.PrepareAuthorityInstanceForMsal()
at Microsoft.Identity.Web.TokenAcquisition.BuildConfidentialClientApplication(MergedOptions mergedOptions)
at Microsoft.Identity.Web.TokenAcquisition.GetOrBuildConfidentialClientApplication(MergedOptions mergedOptions)
at Microsoft.Identity.Web.TokenAcquisition.<GetAuthenticationResultForUserAsync>d__16.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at Microsoft.Identity.Web.DownstreamWebApi.<CallWebApiForUserAsync>d__5.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at MyNamespace.OnboardingController.<Index>d__19.MoveNext()
Possible solution
Additional context / logs / screenshots / link to code I tried manually configurating the ConfidentialClientApplicationOptions but it made no difference.
services.PostConfigure<ConfidentialClientApplicationOptions>(OpenIdConnectDefaults.AuthenticationScheme,
options =>
{
Configuration.GetSection(PortalAuthenticationConfigSection).Bind(options);
options.EnablePiiLogging = env.IsDevelopment();
Debug.Assert(!string.IsNullOrEmpty(options.Instance), "!string.IsNullOrEmpty(options.Instance)");
});
The above code runs ok and i can confirm that Instance was not null at that point but it some how still gets overwritten somewhere
Add any other context about the problem here, such as logs and screenshots, or even links to code.
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 18
See PR: https://github.com/AzureAD/microsoft-identity-web/pull/1672
Upon further investigation it seems that the problem might be in Microsoft.Identity.Web.TokenAcquisition
For what ever reason when the authentication scheme is not explicitly specified it might not be returning the right scheme. When I explicitly set the authentication scheme to OpenIdConnectionDefaults.AuthenticationScheme it doesn’t throw a null reference exception:
Released in 1.24.0.