.net-coreazure-active-directoryopenid-connectservice-fabric-stateless

Specify custom redirect_uri in a web app that uses Azure AD authentication with oidc and a middleware


I am trying to authenticate an app with Azure AD. It's all good in localhost, it redirects to Azure AD where I enter details to authenticate, and it sends back the token that allows to view the resource. Everything managed behind the scenes with the Microsoft.AspNetCore.Authentication.AzureAD.UI 3.1.10 in an aspnetcore 3.1 application.

My app runs on http://localhost:5000 and I can configure the redirectUri/replyUri at Azure AD for that application to support this url. All good.

The problem is in a different environment when my app runs in a service fabric cluster. I can see the problem

AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application

When I inspect the url I can see that the redirect_uri has some url like this http://12.12.12.12/signin-oidc

The problem is double here. First of all I don't know which IP the cluster is gonna assign. Second, it is http, not https, and that's not supported by Azure AD.

Luckily my app has an external Url with a reverse proxy I can use to access. Something like https://myservicefabriccluster.com/MyApp

That Url I could configure as my redirect_uri in both my application and Azure AD, but I don't know how to do so.

My code has something like this:

services
    .AddAuthentication(AzureADDefaults.AuthenticationScheme)
    .AddAzureAD(options => Configuration.Bind("AzureAd", options));

where I bind my settings.

"AzureAd": {
  "Instance": "https://login.microsoftonline.com/",
  "ClientId": "76245c66-354e-4a94-b34d-...",
  "TenantId": "59c56bd4-ce18-466a-b515-..."
},

I can see the AzureADOptions supports some other parameters such as Domain (not needed) or CallbackPath (which by default is ok being /signin-oidc) but there is nothing similar to ReplyUrl or RedirectUri where I can specify an absolute URL as the callback.

I have found a few similar issues without an answer. Others suggest some kind of tricks like a middleware that rewrites that parameter just before redirecting to Azure AD.

Certainly there must be an easier way to deal with this problem that I expect is not so strange. Any help please?


Solution

  • The solution to overwrite redirect_uri parameter with a custom value is to use the Events available in OpenIdConnect library. This library should be available as it's a dependency for Microsoft.AspNetCore.Authentication.AzureAD.UI, so this is my solution that, in addition to the standard properties for AzureADOptions it adds a flag to determine whether the redirect uri must be overwritten and a value to do so. I hope it's self explanatory

    services
        .AddAuthentication(AzureADDefaults.AuthenticationScheme)
        .AddAzureAD(options => configuration.Bind("AzureAd", options));
    
    var isCustomRedirectUriRequired = configuration.GetValue<bool>("AzureAd:IsCustomRedirectUriRequired");
    if (isCustomRedirectUriRequired)
    {
        services
            .Configure<OpenIdConnectOptions>(
                AzureADDefaults.OpenIdScheme,
                options =>
                {
                    options.Events =
                        new OpenIdConnectEvents
                        {
                            OnRedirectToIdentityProvider = async ctx =>
                            {
                                ctx.ProtocolMessage.RedirectUri =
                                    configuration.GetValue<string>("AzureAd:CustomRedirectUri");
                                await Task.Yield();
                            }
                        };
                });
    }
    
    services
        .AddAuthorization(
            options =>
            {
                options.AddPolicy(
                    PolicyConstants.DashboardPolicy,
                    builder =>
                    {
                        builder
                            .AddAuthenticationSchemes(AzureADDefaults.AuthenticationScheme)
                            .RequireAuthenticatedUser();
                    });
            });
    

    And the appsettings.json would have something like this:

    "AzureAd": {
      "Instance": "https://login.microsoftonline.com/",
      "ClientId": "76245c66-354e-4a94-b34d-...",
      "TenantId": "59c56bd4-ce18-466a-b515-..."
      "IsCustomRedirectUriRequired": true,
      "CustomRedirectUri": "https://platform-cluster-development01.cubictelecom.com:19008/Scheduler/WebApi/signin-oidc"
    },
    

    Notice the IsCustomRedirectUriRequired and CustomRedirectUri are my custom properties that I read explicitly in order to overwrite (or not) the redirect uri query parameter when being redirected to the identity provider (i.e: Azure AD)