Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling downstream Graph fails due to incorrect reply address (AADSTS500112) when behind a TLS termination proxy #3114

Open
oddeirik opened this issue Oct 28, 2024 · 2 comments
Labels
answered question Further information is requested

Comments

@oddeirik
Copy link

Microsoft.Identity.Web Library

Microsoft.Identity.Web

Microsoft.Identity.Web version

3.2.2

Web app

Sign-in users and call web APIs

Web API

Protected web APIs call downstream web APIs

Token cache serialization

In-memory caches

Description

I've added the Microsoft.Identity.Web.GraphServiceClient package to an ASP Net Core 8 web application because we want to do some graph calls on behalf of the user.

Prior to this we've had AAD authentication enabled and working for this application, it's just the graph part that's new.

This works fine locally, but when deployed to Azure (linux container app service) it fails with an HTTP 500. Checking the logs for the application, it looks like the downstream call to acquire a token fails because it doesn't pick up the correct scheme for the redirect URL/reply address.

We've already enabled forwarding of headers to ensure this worked for AAD authentication, and this does pick up the correct scheme and works fine.

I was able to reproduce this locally by adding Caddy in front of the application.

Here are some snippets from Program.cs for the sections adding forwarded headers and the authentication parts, based on the documentation at https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-8.0:

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                               ForwardedHeaders.XForwardedProto;

    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();
});

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(configurationSection: builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi(["user.read"])
    .AddMicrosoftGraph()
    .AddInMemoryTokenCaches();

// [...]
var app = builder.Build();
app.UseForwardedHeaders();
app.UseHsts();

The error message being logged:

Microsoft.Identity.Client.MsalServiceException: A configuration issue is preventing authentication - check the error message from the server for details. You can modify the configuration in the application registration portal. See https://aka.ms/msal-net-invalid-client for details.  Original exception: AADSTS500112: The reply address 'http://localhost:4443/signin-oidc' does not match the reply address 'https://localhost:4443/signin-oidc' provided when requesting Authorization code.

The behavior is exactly the same as when running this in an Azure Linux container, it's just a different redirect URL, of course. And AAD authentication without the downstream API call works just fine in both cases, e.g. if I remove the graph-related extension method calls.

Are there additional configuration options that need to be set for the GraphServiceClient to pick up the correct redirect URL (well, the scheme, at least), or is this actually a bug?

Reproduction steps

  1. Add the graph client Nuget package, Microsoft.Identity.Web.GraphServiceClient.
  2. Add downstream graph calls to the application:
	// Existing AAD auth, works fine
    builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
      .AddMicrosoftIdentityWebApp(configurationSection: builder.Configuration.GetSection("AzureAd"))
      // These are new
      .EnableTokenAcquisitionToCallDownstreamApi(["user.read"])
      .AddMicrosoftGraph()
      .AddInMemoryTokenCaches();
  1. Run the application as HTTP behind a TLS-terminating proxy like Azure Linux Container.

Error message

[09:00:03 DBG] False MSAL 4.65.0.0 MSAL.NetCore .NET 8.0.10 Linux [2024-10-28 09:00:03Z - d5457b33-e74f-46bc-a4b7-f80a119426fe] [HttpManager] Received response. Status code: BadRequest.
[09:00:03 DBG] False MSAL 4.65.0.0 MSAL.NetCore .NET 8.0.10 Linux [2024-10-28 09:00:03Z - d5457b33-e74f-46bc-a4b7-f80a119426fe] Finished [HttpManager] ExecuteAsync in 159 ms
[09:00:03 INF] False MSAL 4.65.0.0 MSAL.NetCore .NET 8.0.10 Linux [2024-10-28 09:00:03Z - d5457b33-e74f-46bc-a4b7-f80a119426fe] Response status code does not indicate success: 400 (BadRequest).
[09:00:03 WRN] False MSAL 4.65.0.0 MSAL.NetCore .NET 8.0.10 Linux [2024-10-28 09:00:03Z - d5457b33-e74f-46bc-a4b7-f80a119426fe] Request retry failed.
[09:00:03 DBG] False MSAL 4.65.0.0 MSAL.NetCore .NET 8.0.10 Linux [2024-10-28 09:00:03Z - d5457b33-e74f-46bc-a4b7-f80a119426fe] Finished [Oauth2Client] Sending POST request in 162 ms
[09:00:03 DBG] False MSAL 4.65.0.0 MSAL.NetCore .NET 8.0.10 Linux [2024-10-28 09:00:03Z - d5457b33-e74f-46bc-a4b7-f80a119426fe] [Oauth2Client] Processing error response
[09:00:03 INF] False MSAL 4.65.0.0 MSAL.NetCore .NET 8.0.10 Linux [2024-10-28 09:00:03Z - d5457b33-e74f-46bc-a4b7-f80a119426fe] HttpStatusCode: 400: BadRequest
[09:00:03 ERR] False MSAL 4.65.0.0 MSAL.NetCore .NET 8.0.10 Linux [2024-10-28 09:00:03Z - d5457b33-e74f-46bc-a4b7-f80a119426fe] === Token Acquisition (1000) failed.
Host: login.microsoftonline.com.
[09:00:03 ERR] False MSAL 4.65.0.0 MSAL.NetCore .NET 8.0.10 Linux [2024-10-28 09:00:03Z - d5457b33-e74f-46bc-a4b7-f80a119426fe] Exception type: Microsoft.Identity.Client.MsalServiceException
, ErrorCode: invalid_client
HTTP StatusCode 400
CorrelationId d5457b33-e74f-46bc-a4b7-f80a119426fe
Microsoft Entra ID Error Code AADSTS500112
To see full exception details, enable PII Logging. See https://aka.ms/msal-net-logging

[09:00:03 DBG] False MSAL 4.65.0.0 MSAL.NetCore .NET 8.0.10 Linux [2024-10-28 09:00:03Z - d5457b33-e74f-46bc-a4b7-f80a119426fe] Finished TokenClient:SendTokenRequestAsync in 196 ms
[09:00:03 ERR] False MSAL 4.65.0.0 MSAL.NetCore .NET 8.0.10 Linux [2024-10-28 09:00:03Z - d5457b33-e74f-46bc-a4b7-f80a119426fe] Exception type: Microsoft.Identity.Client.MsalServiceException
, ErrorCode: invalid_client
HTTP StatusCode 400
CorrelationId d5457b33-e74f-46bc-a4b7-f80a119426fe
Microsoft Entra ID Error Code AADSTS500112
To see full exception details, enable PII Logging. See https://aka.ms/msal-net-logging
at Microsoft.Identity.Client.OAuth2.OAuth2Client.ThrowServerException(HttpResponse response, RequestContext requestContext)
at Microsoft.Identity.Client.OAuth2.OAuth2Client.CreateResponse[T](HttpResponse response, RequestContext requestContext)
at Microsoft.Identity.Client.OAuth2.OAuth2Client.ExecuteRequestAsync[T](Uri endPoint, HttpMethod method, RequestContext requestContext, Boolean expectErrorsOn200OK, Boolean addCommonHeaders, Func2 onBeforePostRequestData) at Microsoft.Identity.Client.OAuth2.TokenClient.SendHttpAndClearTelemetryAsync(String tokenEndpoint, ILoggerAdapter logger) at Microsoft.Identity.Client.OAuth2.TokenClient.SendHttpAndClearTelemetryAsync(String tokenEndpoint, ILoggerAdapter logger) at Microsoft.Identity.Client.OAuth2.TokenClient.SendTokenRequestAsync(IDictionary2 additionalBodyParameters, String scopeOverride, String tokenEndpointOverride, CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.SendTokenRequestAsync(IDictionary2 additionalBodyParameters, CancellationToken cancellationToken) at Microsoft.Identity.Client.Internal.Requests.ConfidentialAuthCodeRequest.ExecuteAsync(CancellationToken cancellationToken) at Microsoft.Identity.Client.Internal.Requests.RequestBase.<>c__DisplayClass11_1.<<RunAsync>b__1>d.MoveNext() --- End of stack trace from previous location --- at Microsoft.Identity.Client.Utils.StopwatchService.MeasureCodeBlockAsync(Func1 codeBlock)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.RunAsync(CancellationToken cancellationToken)

[09:00:03 INF] [MsIdWeb] An error occured during token acquisition: Exception occurred while adding an account to the cache from the auth code.
MSAL.NetCore.4.65.0.0.MsalServiceException:
ErrorCode: invalid_client
Microsoft.Identity.Client.MsalServiceException: A configuration issue is preventing authentication - check the error message from the server for details. You can modify the configuration in the application registration portal. See https://aka.ms/msal-net-invalid-client for details. Original exception: AADSTS500112: The reply address 'http://localhost:4443/signin-oidc' does not match the reply address 'https://localhost:4443/signin-oidc' provided when requesting Authorization code. Trace ID: 6f361eeb-cad3-4383-9635-847ff5da5700 Correlation ID: d5457b33-e74f-46bc-a4b7-f80a119426fe Timestamp: 2024-10-28 09:00:03Z
at Microsoft.Identity.Client.OAuth2.OAuth2Client.ThrowServerException(HttpResponse response, RequestContext requestContext)
at Microsoft.Identity.Client.OAuth2.OAuth2Client.CreateResponse[T](HttpResponse response, RequestContext requestContext)
at Microsoft.Identity.Client.OAuth2.OAuth2Client.ExecuteRequestAsync[T](Uri endPoint, HttpMethod method, RequestContext requestContext, Boolean expectErrorsOn200OK, Boolean addCommonHeaders, Func2 onBeforePostRequestData) at Microsoft.Identity.Client.OAuth2.TokenClient.SendHttpAndClearTelemetryAsync(String tokenEndpoint, ILoggerAdapter logger) at Microsoft.Identity.Client.OAuth2.TokenClient.SendHttpAndClearTelemetryAsync(String tokenEndpoint, ILoggerAdapter logger) at Microsoft.Identity.Client.OAuth2.TokenClient.SendTokenRequestAsync(IDictionary2 additionalBodyParameters, String scopeOverride, String tokenEndpointOverride, CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.SendTokenRequestAsync(IDictionary2 additionalBodyParameters, CancellationToken cancellationToken) at Microsoft.Identity.Client.Internal.Requests.ConfidentialAuthCodeRequest.ExecuteAsync(CancellationToken cancellationToken) at Microsoft.Identity.Client.Internal.Requests.RequestBase.<>c__DisplayClass11_1.<<RunAsync>b__1>d.MoveNext() --- End of stack trace from previous location --- at Microsoft.Identity.Client.Utils.StopwatchService.MeasureCodeBlockAsync(Func1 codeBlock)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.RunAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.ApiConfig.Executors.ConfidentialClientExecutor.ExecuteAsync(AcquireTokenCommonParameters commonParameters, AcquireTokenByAuthorizationCodeParameters authorizationCodeParameters, CancellationToken cancellationToken)
at Microsoft.Identity.Web.TokenAcquisition.AddAccountToCacheFromAuthorizationCodeAsync(AuthCodeRedemptionParameters authCodeRedemptionParameters)
StatusCode: 400
ResponseBody: {"error":"invalid_client","error_description":"AADSTS500112: The reply address 'http://localhost:4443/signin-oidc' does not match the reply address 'https://localhost:4443/signin-oidc' provided when requesting Authorization code. Trace ID: 6f361eeb-cad3-4383-9635-847ff5da5700 Correlation ID: d5457b33-e74f-46bc-a4b7-f80a119426fe Timestamp: 2024-10-28 09:00:03Z","error_codes":[500112],"timestamp":"2024-10-28 09:00:03Z","trace_id":"6f361eeb-cad3-4383-9635-847ff5da5700","correlation_id":"d5457b33-e74f-46bc-a4b7-f80a119426fe"}
Headers: Cache-Control: no-store, no-cache
Pragma: no-cache
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
client-request-id: d5457b33-e74f-46bc-a4b7-f80a119426fe
x-ms-request-id: 6f361eeb-cad3-4383-9635-847ff5da5700
x-ms-ests-server: 2.1.19267.5 - WEULR1 ProdSlices
x-ms-clitelem: 1,500112,0,,
x-ms-srs: 1.P
X-XSS-Protection: 0
Set-Cookie: fpc=AuSJN61grv9AnMYA8fc7wHCYKtoUAQAAAJJJsd4OAAAA; expires=Wed, 27-Nov-2024 09:00:03 GMT; path=/; secure; HttpOnly; SameSite=None, x-ms-gateway-slice=estsfd; path=/; secure; httponly
Date: Mon, 28 Oct 2024 09:00:03 GMT

Id Web logs

No response

Relevant code snippets

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                               ForwardedHeaders.XForwardedProto;

    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();
});

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(configurationSection: builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi(["user.read"])
    .AddMicrosoftGraph()
    .AddInMemoryTokenCaches();

// [...]
var app = builder.Build();
app.UseForwardedHeaders();
app.UseHsts();

Regression

No response

Expected behavior

The GraphServiceClient should pick up the correct redirect URL, same as the AAD authentication does.

@oddeirik oddeirik changed the title Calling downstream Graph fails due to incorrect reply address (AADSTS500112) Calling downstream Graph fails due to incorrect reply address (AADSTS500112) when behind a TLS termination proxy Oct 28, 2024
@jmprieur
Copy link
Collaborator

@jmprieur jmprieur added question Further information is requested answered and removed untriaged needs attention labels Oct 29, 2024
@oddeirik
Copy link
Author

Yes, I have tried setting the "ASPNETCORE_FORWARDEDHEADERS_ENABLED"=true environment variable as well.

But according to that Wiki article it also sounds like the "proper" fix (?) in those cases is to configure the forwarded headers middleware, which is what we already have in place.

And this works fine for AAD authentication, it detects the correct scheme and the redirect works. But not for the downstream token acquisition for the graph client.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
answered question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants