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

The provided ConfidentialClientApplicationOptions.RedirectUri is not honored when Web App requests access token for the downstream API #784

Closed
1 of 8 tasks
vh-vahan opened this issue Nov 24, 2020 · 7 comments
Assignees
Labels
enhancement New feature or request fixed
Milestone

Comments

@vh-vahan
Copy link

Which version of Microsoft Identity Web are you using?
Note that to get help, you need to run the latest version.
Microsoft Identity Web 1.3.0

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 in development

Repro

services.AddAuthentication("OpenIdConnect")
	.AddMicrosoftIdentityWebApp(
		msIdentityOptions =>
		{
			msIdentityOptions.ClientId = myWebAppClientId;
			msIdentityOptions.Scope.Add(myWebApiScope);

			msIdentityOptions.Events.OnRedirectToIdentityProvider = context =>
			{
				context.ProtocolMessage.RedirectUri = clusterLoadBalancedUri;
				return Task.CompletedTask;
			};

			msIdentityOptions.Instance = Instance;
			msIdentityOptions.Domain = Domain;
			msIdentityOptions.TenantId = TenantId;
                        .........
		})
	.EnableTokenAcquisitionToCallDownstreamApi(
		confidentialClientApplicationOptions =>
		{
			confidentialClientApplicationOptions.RedirectUri = clusterLoadBalancedUri;

			confidentialClientApplicationOptions.ClientId = myWebAppClientId;
			confidentialClientApplicationOptions.Instance = Instance;
			confidentialClientApplicationOptions.TenantId = TenantId;
		})
	.AddInMemoryTokenCaches();

Expected behavior
confidentialClientApplicationOptions.RedirectUri is used when provided.

Actual behavior
I have an ASP.NET Core web app that calls a downstream web API, and being deployed into Service Fabric cluster. The Web App's redirect URI in app registration portal is configured to be the load balanced URI of the cluster and also localhost.

It works on local environment when the app is deployed locally.
But I get exception when it runs on the cluster -

Exception occurred while processing the request.
System.Exception: An error was encountered while handling the remote login.
---> MSAL.NetCore.4.18.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.
Original exception: AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application: "my app id".

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)
at Microsoft.Identity.Client.OAuth2.OAuth2Client.GetTokenAsync(Uri endPoint, RequestContext requestContext, Boolean addCommonHeaders)
at Microsoft.Identity.Client.OAuth2.TokenClient.SendHttpAndClearTelemetryAsync(String tokenEndpoint)
at Microsoft.Identity.Client.OAuth2.TokenClient.SendHttpAndClearTelemetryAsync(String tokenEndpoint)
at Microsoft.Identity.Client.OAuth2.TokenClient.SendTokenRequestAsync(IDictionary2 additionalBodyParameters, String scopeOverride, String tokenEndpointOverride, CancellationToken cancellationToken) at Microsoft.Identity.Client.Internal.Requests.RequestBase.SendTokenRequestAsync(String tokenEndpoint, IDictionary2 additionalBodyParameters, CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.ConfidentialAuthCodeRequest.ExecuteAsync(CancellationToken cancellationToken)
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(AuthorizationCodeReceivedContext context, IEnumerable`1 scopes)
at Microsoft.Identity.Web.MicrosoftIdentityWebAppAuthenticationBuilder.<>c__DisplayClass10_1.<b__1>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.RunAuthorizationCodeReceivedEventAsync(OpenIdConnectMessage authorizationResponse, ClaimsPrincipal user, AuthenticationProperties properties, JwtSecurityToken jwt)
at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleRemoteAuthenticateAsync()
StatusCode: 400
ResponseBody: {"error":"invalid_client","error_description":"AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application: 'my app id'.}

--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)

I think confidentialClientApplicationOptions.RedirectUri is not being honored and instead it uses the redirect uri constructed from the cluster node's IP.

Possible solution

https://github.com/AzureAD/microsoft-identity-web/blob/9bdf816d2f0e8fd029328ad11cf33217da963ba9/src/Microsoft.Identity.Web/TokenAcquisition.cs#L470
TokenAcquisition. BuildConfidentialClientApplicationAsync method checks for the configured redirectUri.

Additional context / logs / screenshots
Add any other context about the problem here, such as logs and screenshots.

@jmprieur jmprieur added the question Further information is requested label Nov 24, 2020
@jmprieur
Copy link
Collaborator

@vh-vahan : you need to add the redirect URI corresponding to your deployed app to the app registration in the portal.
https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app#add-a-redirect-uri

@vh-vahan
Copy link
Author

Thanks @jmprieur for prompt response.
I added the redirect URI - which is the cluster's load balanced DNS URI. I don't think I should add the URI of each Service Fabric's node instance URI to the app registration portal. Those will be several depending on cluster's node number and also they are not accessible from outside of the cluster.

I added this and it is being honored during the sign in flow

msIdentityOptions.Events.OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.RedirectUri = clusterLoadBalancedUri; //this is honored
return Task.CompletedTask;
};

and I expected to get similar experience when configuring the token acquisition part as well so OnAuthorizationCodeReceived event it could successfully get the token and cache.

.EnableTokenAcquisitionToCallDownstreamApi(
confidentialClientApplicationOptions =>
{
confidentialClientApplicationOptions.RedirectUri = clusterLoadBalancedUri; //this is not honored
})

@vh-vahan
Copy link
Author

@jmprieur so wondering how can I configure or make it to take into account the provided RedirectURI.
Otherwise considering application deployed to service fabric cluster's multi node scale set, it becomes not feasible to register every node's IP based URI in the registration portal.

Instead I register in the portal the cluster's load balanced URI and configure the same URI in application code to be used as redirectURI.

Though it fails and i see here BuildConfidentialClientApplicationAsync() it does not check for the provided redirectURI and constructs it from the current request.

What do you think? Any recommendation for this scenario.

@jmprieur
Copy link
Collaborator

@vh-vahan : Let me rephrase if I understand the scenario.

  • your deployed app is running at a specific URI, behind a load balancer
  • Microsoft.Identity.Web builds the reply URI using that particular URI where the app is running
  • however you would want the redirect URI to be another URL, which is the one of the load balancer.
  • which you'd want to specify with the ConfidentialClientApplication.RedirectURI setting ?

@jmprieur jmprieur added the enhancement New feature or request label Nov 30, 2020
@jmprieur jmprieur added this to the 1.4.0 milestone Nov 30, 2020
@jmprieur
Copy link
Collaborator

@jennyf19 : proposing to do the following:
In

If ConfidentialClientApplication.RedirectUri is not null and is absolute, then we use it
otherwise we do as today (compute it from the URI where the app is running)

@jmprieur jmprieur removed the question Further information is requested label Nov 30, 2020
@vh-vahan
Copy link
Author

@vh-vahan : Let me rephrase if I understand the scenario.

  • your deployed app is running at a specific URI, behind a load balancer
  • Microsoft.Identity.Web builds the reply URI using that particular URI where the app is running
  • however you would want the redirect URI to be another URL, which is the one of the load balancer.
  • which you'd want to specify with the ConfidentialClientApplication.RedirectURI setting ?

Thanks @jmprieur, yes, that is the scenario I have, and thanks for including that work in 1.4.0 version.

@jennyf19
Copy link
Collaborator

jennyf19 commented Dec 9, 2020

Included in 1.4 Release.

@jennyf19 jennyf19 closed this as completed Dec 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request fixed
Projects
None yet
Development

No branches or pull requests

3 participants