Microsoft Identity Web: Change Redirect Uri
Z

5

9

I am using .net 5, Identity Web Ui to access Microsoft Graph. Where can I configure my Redirect URI?

I need to specify the full Uri, since the generated one from callbackUri is incorrect due to being behind a Load Balancer with SSL offload.

Here is my current ConfigureServices section

    services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
            .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
            .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
            .AddInMemoryTokenCaches();
Zama answered 16/3, 2021 at 11:41 Comment(6)
Do you mean you want to configure the redirect url on App registration side: learn.microsoft.com/en-us/azure/active-directory/develop/…?Heall
@AllenWu I need to configure the URL that my application sends as the callback url so that it matches the one in the registration.Zama
did you manage to do it?Libertinage
@Libertinage No, enabled SSL from load balancer to web server. Which happens to be my production config anyway. Would still like to know the answer.Zama
I was struggling with a similar issue for three days, I managed to do it today at work, I'm gonna post an answerLibertinage
Having a similar issue and found this article. The problem is likely to be in the gateway>app communication and overwriting it one place is a workaround. Other redirects like authorization are likely to fail. A potential solution is to stop using host name from backend address and add dns entry to app servce custom domain: techcommunity.microsoft.com/t5/apps-on-azure-blog/…Adolpho
L
11

I was facing a similar problem with a WebApp exposed only behind a front door, the WebApp had to call a custom downstream WebApi.

My service configuration that worked on my localhost dev machine:

// AzureAdB2C
        services
            .AddMicrosoftIdentityWebAppAuthentication(
                Configuration,
                "AzureAdB2C", subscribeToOpenIdConnectMiddlewareDiagnosticsEvents: true)
            .EnableTokenAcquisitionToCallDownstreamApi(p =>
                {
                    p.RedirectUri = redUri; // NOT WORKING, WHY?
                    p.EnablePiiLogging = true;
                },
                [... an array with my needed scopes]
            )
            .AddInMemoryTokenCaches();

I tried the AddDownstreamWebApi but did not manage to make it work so I just fetched the needed token with ITokenAcquisition and added it to an HttpClient to make my request.

Then I needed AzureAd/B2C login redirect to the uri with the front door url: https://example.org/signin-oidc and things broke. I solved it like this:

First of all you have to add this url to your App registration in the azure portal, very important is case sensitive it cares about trailing slashes and I suspect having many urls that point to the very same controller and the order of these have some impact, I just removed everything and kept the bare minimum.

Then in the configure services method:

services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
        {
            options.SaveTokens = true; // this saves the token for the downstream api
            options.Events = new OpenIdConnectEvents
            {
                OnRedirectToIdentityProvider = async ctxt =>
                {
                    // Invoked before redirecting to the identity provider to authenticate. This can be used to set ProtocolMessage.State
                    // that will be persisted through the authentication process. The ProtocolMessage can also be used to add or customize
                    // parameters sent to the identity provider.
                    ctxt.ProtocolMessage.RedirectUri = "https://example.org/signin-oidc";
                    await Task.Yield();
                }
            };
        });

With that the redirect worked, but I entered a loop between the protected page and the AzureB2C login.

After a succesful login and a correct redirect to the signin-oidc controller (created by the Identity.Web package) I was correctly redirected again to the page that started all this authorization thing, but there it did not find the authorization. So I added/modded also this:

services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
            options.Secure = CookieSecurePolicy.Always;
        });

With this the authorization worked, but I was not able to get the token to call the downstream API, before this redirect thing ITokenAcquisition worked, but now when trying to get the token it throws an exception.

So in my controller/service to get the token I modified and used:

var accessToken = await _contextAccessor.HttpContext
                .GetTokenAsync(OpenIdConnectDefaults.AuthenticationScheme, "access_token");

So now with the token I add it to my HttpRequestMessage like this:

request.Headers.Add("Authorization", $"Bearer {accessToken}");

I lived on StackOverflow and microsoft docs for 3 days, I am not sure this is all "recommended" but this worked for me.

Libertinage answered 28/4, 2021 at 19:14 Comment(1)
amazing. I was able to enable SSL and have mine work, but I will accept this as correct way to work around this.Zama
C
8

I had the same problem running an asp.net application under Google Cloud Run, which terminates the TLS connection. I was getting the error: AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application.

Using fiddler, I examined the request to login.microsoftonline.com and found that the query parameter redirect_uri exactly matched the url I'd configured in the application in Azure except that it started http rather than https.

I initially tried the other answers involving handling the OpenIdConnectEvents event and updating the redirect uri. This fixed the redirect_url parameter in the call to login.microsoftonline.com and it then worked until I added in the graph api. Then I found my site's signin-oidc page would give its own error about the redirect uri not matching. This would then cause it to go into a loop between my site and login.microsoftonline.com repeatedly trying to authenticate until eventually I'd get a login failure.

On further research ASP.net provides middleware to properly handle this scenario. Your SSL load balancer should add the standard header X-Forwarded-Proto with value HTTPS to the request. It should also send the X-Forwarded-For header with the originating IP address which could be useful for debugging, geoip etc.

In your ASP.net application, to configure the middleware:

services.Configure<ForwardedHeadersOptions>(options =>
 {
   options.ForwardedHeaders =
       ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
   options.KnownNetworks.Clear();
   options.KnownProxies.Clear();
 });

Then enable the middleware:

app.UseForwardedHeaders();

Importantly, you must include this before the calls to app.UseAuthentication/app.UseAuthorization that depends on it.

Source: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-5.0

If your load balancer doesn't add the X-Forwarded-Proto header and can't be configured to do so then the document above outlines other options.

Cascade answered 1/3, 2022 at 11:2 Comment(2)
Very interesting, I'll have to check my headers for thisZama
I had the exact same problem, I was behind a proxy that terminate the TLS connection. The app can see only http connection on port 80 and without the forwarding it tries to redirect on http instead of https. Was trying everything and only your solution worked. Thanks a lot !!!Bakerman
M
2

I was facing with similar issue for 3 days. The below code helped me to get out of the issue.

string[] initialScopes = Configuration.GetValue<string>("CallApi:ScopeForAccessToken")?.Split(' ');

        services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAd")
            .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
            .AddInMemoryTokenCaches();
        services.AddControllers();
        services.AddRazorPages().AddMvcOptions(options =>
        {
            var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser().Build();
            options.Filters.Add(new AuthorizeFilter(policy));

        }).AddMicrosoftIdentityUI();
        services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
        {
            options.SaveTokens = true; // this saves the token for the downstream api
            options.Events = new OpenIdConnectEvents
            {
                OnRedirectToIdentityProvider = async ctxt =>
                {

                    ctxt.ProtocolMessage.RedirectUri = "https://example.org/signin-oidc";
                    await Task.Yield();
                }
            };
        });
Metabolism answered 12/1, 2022 at 15:41 Comment(0)
K
1

I stumbled upon the same issue using a .NET Core 8. app behind a frontdoor that is not forwarding the host headers correctly.

I used middleware to override the HttpRequest.Host value because that is what Microsoft.AspNetCore.Authentication is using in

protected string BuildRedirectUri(string targetPath)
        => Request.Scheme + Uri.SchemeDelimiter + Request.Host + OriginalPathBase + targetPath;

public class HostOverrideMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly IConfiguration _configuration;
        public HostOverrideMiddleware(RequestDelegate next, IConfiguration configuration)
        {
            _next = next;
            _configuration = configuration;
        }

        public async Task Invoke(HttpContext context)
        {

            context.Request.Host = new HostString(_configuration["setconfigkeyhere"]);

            await _next(context);
        }
    }

var app = builder.Build();
app.UseMiddleware<HostOverrideMiddleware>();

Khaki answered 17/1 at 16:4 Comment(0)
F
0

I had a problem where Azure Container Apps wouldn't work with Microsoft.Identity.Web, because the containerized application thought it was served from a http://.. path and not https. In addition to the OnRedirectToIdentityProvider, I also had to override the OnTokenValidated event. The code I used:

builder.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    options.Events = new OpenIdConnectEvents
    {
        OnRedirectToIdentityProvider = ctxt =>
        {
            string? redirectUri = ctxt.HttpContext.RequestServices.GetRequiredService<IConfiguration>()["RedirectUri"];
            if (redirectUri is not null)
            {
                ctxt.ProtocolMessage.RedirectUri = redirectUri;
            }
            ctxt.ProtocolMessage.Prompt = "select_account";
            return Task.CompletedTask;
        },
        OnTokenValidated = ctxt =>
        {
            string? redirectUri = ctxt.HttpContext.RequestServices.GetRequiredService<IConfiguration>()["RedirectUri"];
            if (redirectUri is not null)
            {
                ctxt.ProtocolMessage.RedirectUri = redirectUri;
            }
            return Task.CompletedTask;
        }
    };
});
Furry answered 15/9 at 19:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.