identityserver3openid-connectappharbor

Why is IdentityServer redirecting to http rather than https?


I have a very simple MVC5 website that I'm trying to secure with IdentityServer3.

Both my website and my IdentityServer instance are hosted as separate sites in AppHarbor. Both are behind https.

When I hit a resource in my website that is protected by an [Authorize] attribute (e.g., /Home/About), I am successfully redirected to IdentityServer, and I can successfully authenticate.

When IdentityServer POSTs its response back to the website (via app.FormPostResponse.js), the website responds with a 302 redirect to the requested resource - as expected. However, this redirect is to http, not https (see the network trace below).

I'm sure this is just something wrong with my IdentityServer config, but I'd appreciate any pointers as to what I've got wrong.

(AppHarbor uses a reverse proxy (nginx I believe) in front of IIS, where SSL terminates - so I have RequireSsl = false for this scenario, as per the IdentityServer documentation.)

Here is my website's Startup.cs

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "Cookies"
        });

        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            Authority = "https://<my-idsrv3>.apphb.com/identity",

            ClientId = "<my-client-id>",
            Scope = "openid profile roles email",
            RedirectUri = "https://<my-website>.apphb.com",
            ResponseType = "id_token",

            SignInAsAuthenticationType = "Cookies",

            UseTokenLifetime = false
        });

        JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
    }
}

Here is Startup.cs from my IdentityServer3 instance:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Map("/identity", idsrvApp =>
        {
            idsrvApp.UseIdentityServer(new IdentityServerOptions
            {
                SiteName = "My Identity Server",
                SigningCertificate = Certificates.LoadSigningCertificate(),
                RequireSsl = false,
                PublicOrigin = "https://<my-idsrv3>.apphb.com",

                Factory = new IdentityServerServiceFactory()
                    .UseInMemoryUsers(Users.Get())
                    .UseInMemoryClients(Clients.Get())
                    .UseInMemoryScopes(Scopes.Get())
            });
        });
    }
}

Here is the definition of my website Client:

new Client
{
    Enabled = true,
    ClientName = "My Website Client",
    ClientId = "<my-client-id>",
    Flow = Flows.Implicit,

    RedirectUris = new List<string>
    {
        "https://<my-website>.apphb.com"
    },

    AllowAccessToAllScopes = true
}

Here is the trace from Chrome, after clicking 'Yes, Allow' on the IdentityServer consent screen:

Chrome network trace


Solution

  • So it looks like this issue was caused by my client website being behind an SSL-terminating nginx front-end.

    With reference to this GitHub issue, I added the following to the start of my website's app configuration:

    app.Use(async (ctx, next) =>
    {
        string proto = ctx.Request.Headers.Get("X-Forwarded-Proto");
        if (!string.IsNullOrEmpty(proto))
        {
            ctx.Request.Scheme = proto;
        }
        await next();
    });
    

    This makes the website aware that incoming requests were over https; this in turn appears to ensure that the IdentityServer3 middleware generates https uri's.