Search code examples
c#azure-active-directorymicrosoft-graph-apiazure-ad-msalmicrosoft-identity-web

Microsoft Identity Web: Change Redirect Uri


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();

Solution

  • 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.