Swashbuckle.webapi: https not working for swashbuckle.core in owin host

Created on 24 Apr 2015  路  20Comments  路  Source: domaindrivendev/Swashbuckle.WebApi

I have the hosted the owin as SSL enabled. Without SSL i can able to see the swagger ui documentation. what is the procedure to get the Swagger UI with SSL enabled.

The following code i have added in the startup.cs of owinhost.

config
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "Desigo");
c.Schemes(new[] { "http", "https" });
c.IncludeXmlComments(GetXmlCommentsPath());
}
)
.EnableSwaggerUi();

Kidly provide your suggestion

Most helpful comment

For those running in a proxy environment, as long as you have the following headers it should create the correct base path:

  • X-Forwarded-Proto
  • X-Forwarded-Host
  • X-Forwarded-Port

We fixed the issue by updating the headers our proxy server was passing.

All 20 comments

Hmmm, SSL should just work out-of-the-box.

As a matter of interest, what happens if you remove the c.Schemes line above. If schemes are not explicitly provided in the swagger description, the UI will assume the same scheme that it's currently being served through. So, to access SSL protected methods, you would need to view the swagger-ui via the https scheme.

Also, could you elaborate on the error scenario? Do you see an error, nothing, a JavaScript error?

swaggerissue

Nothing is displayed in console when I am trying to browse in https, my owin is hosted successfully in console application with https enabled.

And also I have another doubt,
Is it possible to inject swagger-ui.js in swashbuckle.core?

Kindly provide your suggestion

swaggerissue

Nothing is displayed in console when I am trying to browse in https, my owin is hosted successfully in console application with https enabled.

And also I have another doubt,
Is it possible to inject swagger-ui.js in swashbuckle.core?

Kindly provide your suggestion

That looks more like a web server issue than an application issue. Have you confirmed you can access a regular page/API endpoint in your website (i.e. not the swagger ones) via the scheme, host and port in your browser above?

Yes.. It is working perfectly for the regular endpoint. Only swagger is not working. Kindly suggests what am i missing in configuration.

Hi, It is not working when i am hosting(OWIN) the web api in https. This query is not interlinked with #295. I am looking for your suggestions. Please see my query which i mentioned above

Doesn't work here either.

I go to a https:// url for my Web API, but what is generated in index:

window.swashbuckleConfig = {
        rootUrl: 'http://my.api.is:80/MyAPI',

Tried to change it with configuration code:

c.RootUrl(req => req.RequestUri.Scheme + "://" + req.RequestUri.Authority + System.Web.VirtualPathUtility.ToAbsolute("~"));

Didn't work. Still generates http:// so I always get:

Mixed Content: The page at 'https://my.api.is/MyAPI/swagger/ui/index' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://my.api.is/MyAPI/swagger/docs/v1'. This request has been blocked; the content must be served over HTTPS.

:+1:

try this way:

using System.Web.Http;
using WebActivatorEx;
using Easy.Docs.API;
using Swashbuckle.Application;
using System.Globalization;
using System.Collections.Generic;
using System.Net.Http;
using System.Web.Http;
using System.Linq;

c.RootUrl(req => GetRootUrlFromAppConfig(req));
private static string GetRootUrlFromAppConfig(System.Net.Http.HttpRequestMessage req)
{
string scheme = GetHeaderValue(req, "X-Forwarded-Proto") ?? req.RequestUri.Scheme;
string host = GetHeaderValue(req, "X-Forwarded-Host") ?? req.RequestUri.Host;
string port = GetHeaderValue(req, "X-Forwarded-Port") ?? req.RequestUri.Port.ToString(CultureInfo.InvariantCulture);

        var httpConfiguration = req.GetConfiguration();
        var virtualPathRoot = httpConfiguration.VirtualPathRoot.TrimEnd('/');

        if (port.Equals("80") || port.Equals("443"))
        {
            return string.Format("{0}://{1}{3}", scheme, host, port, virtualPathRoot);
        }
        else
        {
            return string.Format("{0}://{1}:{2}{3}", scheme, host, port, virtualPathRoot);
        } 
    }

    private static string GetHeaderValue(HttpRequestMessage request, string headerName)
    {
        IEnumerable<string> list;
        return request.Headers.TryGetValues(headerName, out list) ? list.FirstOrDefault() : null;
    }

Based on logic this should work, but it forces HTTP in the window.swashbuckleConfig

I tried to use a custom template for Index, that forced swashbuckleConfig.rootUrl to use https URI like such:

      var rootUrlFromServer = '%(RootUrl)';
      if (window.location.protocol === "https:") {
          rootUrlFromServer = rootUrlFromServer.replace("http:", "https:");
      }

      window.swashbuckleConfig = {
        rootUrl: rootUrlFromServer,
        discoveryPaths: arrayFrom('%(DiscoveryPaths)'),
        booleanValues: arrayFrom('%(BooleanValues)'),
     ...
     ...

And I am still getting http only calls when trying to test out endpoints in my Web API.

Mixed Content: The page at 'https://api.corporate.com/swagger/ui/index#!/..........' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://api.corporate.com/api/resource'. This request has been blocked; the content must be served over HTTPS.

Any word on this?

There's two places where the custom RootUrl lambda (or default implementation) is being used:

1) When serving "index.html", it's used to generate the discovery URL that get's consumed by the swagger-ui JS
2) When responding to the discovery URL, it's used to generate the API "schemes", "host" and "basePath" properties that get returned in the Swagger JSON document. This is then used to generated the AJAX request whenever you click a "Try it out" button in the UI

So, the custom "index.html" approach used above only addresses the first case and not the second. I think the root cause is elsewhere.

Swashbuckle uses the result of the RootUrl lambda to populate these properties directly with one exception - you can override the schemes properties through the Schemes config option. Before reading on, you might want to double check you're not using this.

If not, then there must be something about you're environment that is causing the following code to return "http" instead of "https" for the current request:

req => req.RequestUri.Scheme

I would suggest this is the root cause of your problem. One possibility that comes to mind ... if your hosting your application in a proxy environment where SSL actually gets terminated at the proxy server, you would see this behavior.

Can you confirm any of this?

We are acctually running in a proxy environment, offloading SSL with Netscaler (and communicating HTTP with inside services).
So, yes, that is probably the root cause.

No Luck.. It is not working for https. The configuration is as follows,
config
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "Desigo Access Management API");
c.Schemes(new[] { "http", "https" });
c.RootUrl(req => req.RequestUri.Scheme);
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.FirstOrDefault());
c.IncludeXmlComments(XmlCommentsPath());
}
)
.EnableSwaggerUi();

Issue is fixed..
Changed the configuration as
config
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "Desigo Access Management API");
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.FirstOrDefault());
c.IncludeXmlComments(XmlCommentsPath());
}
)
.EnableSwaggerUi();
and modified the index.html as Mr.Haukurk suggested

Thanks a lot for everyone

Is there any solution for those who are running in a proxy environment? To force HTTPS?

I have the same problem as @gaui and @haukurk and resolved it by forcing HTTPS for swagger:

    .EnableSwagger("docs/{apiVersion}",
    c =>
    {
      ...
      c.RootUrl(ResolveBasePath);
      ...
    })
    .EnableSwaggerUi();

private static string ResolveBasePath(HttpRequestMessage message)
{
    var virtualPathRoot = message.GetRequestContext().VirtualPathRoot;

    var schemeAndHost = "https://" + message.RequestUri.Host;
    return new Uri(new Uri(schemeAndHost, UriKind.Absolute), virtualPathRoot).AbsoluteUri;
}

Of course this does not address the use case where you might want to test both HTTP and HTTPS schemes at runtime, but if you are forcing HTTPS for your services (which you should be) then this is an acceptable solution.

For those running in a proxy environment, as long as you have the following headers it should create the correct base path:

  • X-Forwarded-Proto
  • X-Forwarded-Host
  • X-Forwarded-Port

We fixed the issue by updating the headers our proxy server was passing.

Solution with X-Forwarded-* worked perfectly without any changes in code. Thanks @willdrob !

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Misiu picture Misiu  路  3Comments

johnpmcclung picture johnpmcclung  路  3Comments

qwertykeith picture qwertykeith  路  5Comments

kmmacgill picture kmmacgill  路  3Comments

thj-dk picture thj-dk  路  5Comments