26

I am having trouble with securing my Web API using owin middle ware.

I have installed below package

Install-Package Microsoft.Owin.Cors -Version 2.1.0

And below is ConfigureAuth.cs code.

 public void ConfigureAuth(IAppBuilder app)
 {                
      //...
      app.UseOAuthBearerTokens(OAuthOptions);    
      ///Install-Package Microsoft.Owin.Cors -Version 2.1.0
      app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
  }

I have hosted this WebApi project on a link , say ,http://webaip.azurewebsites.net

I am trying to access controller methods of above API from another site, say , http://mysite.azurewebsites.net With above code in place I am able to invoke all the methods of API which are not secure. (Not decorated with Authorize attribute) Through javascript I am not able to invoke /Token for authentication. Below is my javascript code.

function LogIn() {
            var loginData = {
                grant_type: 'password',
                username: 'username',
                password: 'password',                
            };

            $.ajax({
                type: 'POST',
                url: 'http://webaip.azurewebsites.net/Token/',
                data: loginData               

            }).done(function (data) {
                alert('logged in');
                alert(data);
            }).fail(function (data) {
                alert('login problem')
            }).error(function (data) {
                alert('error invoking API');
            });
            return false;
        }

I am getting below error

XMLHttpRequest cannot load http://webaip.azurewebsites.net/Token/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://mysite.azurewebsites.net' is therefore not allowed access. The response had HTTP status code 404.

Note: I have also tried to use below code with. It's not working for me either.

public static void Register(HttpConfiguration config)
{
     var json = config.Formatters.JsonFormatter;
     config.Formatters.Remove(config.Formatters.XmlFormatter);
     //Need to have  Microsoft.AspNet.WebApi.Cors package installed.
     config.EnableCors(new EnableCorsAttribute("*","*","*"));
}
user2243747
  • 2,767
  • 6
  • 41
  • 61

8 Answers8

49

After many hours of searching and looking at many many different solutions to this i have managed to get this working as per the below.

There are a number of reasons this is happening. Most likely you have CORS enabled in the wrong place or it is enabled twice or not at all.

If you are using Web API and Owin Token end point then you need to remove all the references to CORS in your Web API method and add the correct owin method because web api cors will not work with Token endpoint whilst Owin cors will work for both Web API and Token auth end points so lets begin:

  1. Make sure you have the Owin Cors package installed
  2. Remove any line that you have eg.config.EnableCors(); from your WebAPIconfig.cs file
  3. Go to your startup.cs file and make sure you execute Owin Cors before any of the other configuration runs.

        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
        ConfigureAuth(app);
    
  4. If your still having problems go to: Startup.Auth.cs and ensure you have the following in your ConfigureAuth method (you shouldnt need this if your startup.cs file is correct)

    app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

Piotr Stulinski
  • 9,241
  • 8
  • 31
  • 46
  • 2
    This was the only answer that worked for my team. All the other answers broke the rest of the app. Thanks for explaining the need to remove other CORS config. – SouthShoreAK Oct 22 '15 at 16:11
  • 2
    @SouthShoreAK pleasure i went through the same pain. The only thing i would have to add is that people need to know to add the Owin.Cors package. – Piotr Stulinski Oct 22 '15 at 17:19
  • following up to step 3 is enough for me. – Foyzul Karim Apr 19 '16 at 10:17
  • @PiotrStulinski, you saved my life, spend the whole day for this. – dichen Mar 11 '17 at 01:19
  • Finally its work for me after 3 days on net searching this solution was worked for me i did Step 1 and 2 only..... Thank you very very much.... for this post...... :) – Swapnil Tandel Jul 04 '17 at 13:43
  • I've been searching for a solution for a while and didn't realized there is a Owin CORS and a Web API CORS package. The other thing is the web.config need to be amend according to this article http://benfoster.io/blog/aspnet-webapi-cors – Tien Dinh Jan 31 '18 at 09:12
  • This finally works form also, but the thing was to put the configuration before any configuration, because i already tryed this solution – Rodrigo Apr 24 '18 at 13:32
  • Everything worked fine, I just had to follow this one too https://stackoverflow.com/a/34488826/4367683 – Machado Jun 12 '18 at 13:58
20

the reason you are getting that error is because you have enabled CORS for the webapi but not for your /Token endpoint this gets initialised before the webapi pipeline gets its CORS settings.

So in addition to what you have already done in your WebApiConfig.cs

You should do the following: (assuming you have a standard WebAPI 2 project)

** Open File: App_Start/IdenityConfig.cs ** and add the line following // Allow cors for the ...

I have left the rest untouched as in the normal project template

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        // Allows cors for the /token endpoint this is different from webapi endpoints. 
        context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });  // <-- This is the line you need

        var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<IdentityDb>()));
        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = true,
            RequireUniqueEmail = true
        };
        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = false,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };

       // rest ommited ... 
        return manager;
    }
Max Kimambo
  • 406
  • 4
  • 10
  • 2
    It worked for /token, but start throwing same issue for /api now...:( if I remove the line you mentioned, /api starts working fine... – umair.ali May 22 '15 at 12:51
  • Endless frustration this caused. Thank you for posting your answer--without it I would have lost hours. – Matt Cashatt Nov 23 '15 at 02:47
3

See my answer for this question

Also, if you use an angularJS as your client, you can have a look to my article that shows how to use Web API 2 (Individual User Account + CORS Enabled) from AngularJS Client.

Hope that helps.

Community
  • 1
  • 1
Omar.Alani
  • 4,050
  • 2
  • 20
  • 31
2

This solution can also be used:

open providers folder and then open ApplicationOAuthProvider.cs

inside GrantResourceOwnerCredentials() function paste this line:

context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
Osama Bin Waseem
  • 113
  • 1
  • 1
  • 8
  • In my case the control does not even go to this method.GrantResourceOwnerCredentials how and where should I add the header? – Abi P Sep 24 '15 at 22:46
  • 1
    Hey, Thanks for the follow up, i forgot to update in this thread. I got it working by putting the cors code in public void ConfigureAuth(IAppBuilder app) of the Startup classs. app.UseCors(CorsOptions.AllowAll); – Abi P Sep 28 '15 at 14:00
  • the solution is to REMOVE that like if you have CORS enabled in `Startup.cs` – Toolkit Aug 21 '18 at 15:15
2

In case, anyone finds this useful

app.Use(async (context, next) =>
            {
                context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "http://localhost:52436" });
                await next();

            });
rawel
  • 2,923
  • 21
  • 33
1

You should not have same header twice (I think it is a dictionary data structure)

In my case I had this line in a provider class which was not needed because I'm already enabling cores in startup.cs

//context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

in startup.cs I had and I kept:

app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
Nour Lababidi
  • 414
  • 4
  • 7
0

Had the same problem. Owin and WebAPI conflicting so either worked but not together.

My Solution in Startup.Auth.cs

            {
                var cultureQuery = context.Request.Query["culture"];

                IOwinRequest req = context.Request;
                IOwinResponse res = context.Response;
                if (req.Path.StartsWithSegments(new PathString("/Token")))
                    {
                    // if there is an origin header
                    var origin = req.Headers.Get("Origin");
                    if (!string.IsNullOrEmpty(origin))
                    {
                        // allow the cross-site request
                        res.Headers.Set("Access-Control-Allow-Origin", origin);
                    }
                    // if this is pre-flight request
                    if (req.Method == "OPTIONS")
                    {
                        // respond immediately with allowed request methods and headers
                        res.StatusCode = 200;
                        res.Headers.AppendCommaSeparatedValues("Access-Control-Allow- 
                        Methods", "GET", "POST");
                        res.Headers.AppendCommaSeparatedValues("Access-Control-Allow- 
                        Headers", "authorization");
                        // no further processing
                        return;
                    }
                }


               ...```

Vaughn Gavin
  • 69
  • 1
  • 3
-2

The first step is to install CORS nuget: Microsoft.AspNet.WebApi.Core

Enable it in Startup.cs

        config.EnableCors();

then you can do anything you want:

to allow a controller to expose to external application, add this attribute:

 [EnableCors([theHostYouWant], "*", "*")]

to allow external authentication, application need access to "/Token", to allow this, in

 [YourApiFolder]/Providers/ApplicationoAuthProvider.cs

find

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)

add

        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "[YourDesiredHostAddress]" });

this covers both the controller and "/Token", the attribute can also added in the controller methods. So it can solve all the problem.

Hao
  • 266
  • 1
  • 12