27

I have an API service made with NancyFX, and a couple of front-end developers creating an SPA JS client against this API.

We would like to test the client side code against the published server without having to publish the client code with too much frequency.

But, the client runs at localhost, and the server is at Windows Azure.

Is it possible and easy to enable CORS on the NancyFX server? How can I do that?

Thanks.

Alberto Basalo
  • 273
  • 1
  • 4
  • 5

3 Answers3

31

Its possible to do this in the bootstraper of Nancy

protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
    {

       //CORS Enable
        pipelines.AfterRequest.AddItemToEndOfPipeline((ctx) =>
        {
            ctx.Response.WithHeader("Access-Control-Allow-Origin", "*")
                            .WithHeader("Access-Control-Allow-Methods", "POST,GET")
                            .WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-type");

        });
joce
  • 9,624
  • 19
  • 56
  • 74
oaamados
  • 666
  • 10
  • 17
  • 1
    That's really strange. In this line `WithHeader("Access-Control-Allow-Methods", "POST,GET")` you allow the methos you need. – oaamados Aug 21 '14 at 01:13
27

If you're using IIS to host Nancy, in this case on Windows Azure then you can just update the web.config to add the header to every request.

This can be done by adding the following:

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="*" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

Alternatively you can do what Sunny suggested, and if you don't like writing that every time you can add your own extension method:

public static class NancyExtensions
{
    public static void EnableCors(this NancyModule module)
    {
        module.After.AddItemToEndOfPipeline(x =>
        {
            x.Response.WithHeader("Access-Control-Allow-Origin", "*");
        });
    }
}

Then you can just call this.EnableCors() in your route.

joce
  • 9,624
  • 19
  • 56
  • 74
Phill
  • 18,398
  • 7
  • 62
  • 102
  • Is there any way to secure this? I mean be sure that only a specific client can access the given end point? – Norbert Norbertson Jan 27 '17 at 12:06
  • @NorbertNorbertson When consuming the API, sure, accept request, validate it, return headers only if the consumer is valid. – Phill Jan 27 '17 at 12:12
  • I have an HTML form that posts to a Nancy endpoint. It works but is it possible to allow only a particular domain to post to this endpoint? – Norbert Norbertson Jan 28 '17 at 22:39
  • I think I found an answer here: http://stackoverflow.com/questions/1653308/access-control-allow-origin-multiple-origin-domains. Check HTTP_Origin in the header. – Norbert Norbertson Jan 29 '17 at 09:15
  • Yes. In Nancy I can do this: `var origin = Request.Headers["Origin"].FirstOrDefault();` to get the origin and then only allow a specific domain to use the endpoint. – Norbert Norbertson Jan 29 '17 at 09:51
16

If your HTTP request is simple then Phill's answer will suffice, but if the request is not so simple, the browser will send a preflight check. The preflight check is an OPTIONS HTTP request and this has to be handled too.

Here is an extension method to configure CORS:

public static class MyNancyExtension
{
    public static void EnableCORS(this Nancy.Bootstrapper.IPipelines pipelines)
    {
        pipelines.AfterRequest.AddItemToEndOfPipeline(ctx =>
        {
            if (ctx.Request.Headers.Keys.Contains("Origin"))
            {
                var origins = "" + string.Join(" ", ctx.Request.Headers["Origin"]);
                ctx.Response.Headers["Access-Control-Allow-Origin"] = origins;

                if (ctx.Request.Method == "OPTIONS")
                {
                    // handle CORS preflight request

                    ctx.Response.Headers["Access-Control-Allow-Methods"] =
                        "GET, POST, PUT, DELETE, OPTIONS";

                    if (ctx.Request.Headers.Keys.Contains("Access-Control-Request-Headers"))
                    {
                        var allowedHeaders = "" + string.Join(
                            ", ", ctx.Request.Headers["Access-Control-Request-Headers"]);
                        ctx.Response.Headers["Access-Control-Allow-Headers"] = allowedHeaders;
                    }
                }
            }
        });
    }
}

To enable CORS call this extension method in the bootstrapper:

protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
{
    base.ApplicationStartup(container, pipelines);

    pipelines.EnableCORS();
}

Please note it is not extending NancyModule because OPTIONS is handled outside of module (also here).

Community
  • 1
  • 1
Endy Tjahjono
  • 24,120
  • 23
  • 83
  • 123