CORS error from .NET Core web api even after successfully calling the api - angularjs

So I have an angular cli app with Angular 4 talking to a new .NET Core API project. My environment is Windows 7 and the standard browser used in my organisation is IE 11 (so ultimately needs to work with this, however I want to develop in Chrome or FF as TypeScript / .map files don't work on Windows 7). It's an internal web application and we need to use Windows authentication. I created the .NET Core app with Visual Studio 2017 Community.
TL;DR My problem is that I continually get CORS errors in Chrome and FF, even after hitting the api and successfully returning data from the back end. The bizarre thing is that Chrome and FF successfully call the api when I don't enable CORS on the .NET side. When I try to enable CORS Chrome or FF don't hit the api at all. In either case the client code calls an error handler regardless of whether it can connect to the api or not.
So here's the .NET code I tried (although Chrome and FF both call the api without this). I created a CORS policy in Startup.cs\ConfigureSevices with AllowAnyOrigin and also tried the specific "http://localhost:4200" url (local server the app runs on). Also various combinations of AllowAnyMethod and AllowAnyHeader.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("MyPolicy",
builder =>
{
builder.WithOrigins("http://localhost:4200")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
//...
}
I added the CORS policy globally in Startup.cs\Configure.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors("MyPolicy");
// ...
}
I also tried adding it to the Controller directly as an attribue using [EnableCors]
[Route("api/[controller]")]
[EnableCors("MyPolicy")]
public class CustomerController : Controller
Here's the method on the controller:
// GET: api/customer/id
//[Authorize]
//[EnableCors("MyPolicy")]
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
var customer = await _customerService.GetAsync(id);
if (customer == null)
{
return NotFound();
}
string msJson = JsonConvert.SerializeObject(customer,
JsonCustomSettings.CustomJsonSettings);
return Ok(msJson);
}
I also read that I need to add the withCredentials option to the api call in Angular - here's the Angular code:
getContent(Id: number): Promise<Client[]> {
const headers = new Headers({'Content-Type': 'application/json'});
const options = new RequestOptions({ headers: headers, withCredentials: true });
console.debug('In getContent:' + id);
return this.http.get("http://localhost:13751/api/customer/"+id, options)
.toPromise()
.then(res => this.extractData(res))
.catch(this.handleError);
}
Results:
In Chrome and FF "this.handleError" always gets called. As I said Chrome and FF both call the api and return data successfully when I remove the CORS settings from the api.
When I add any of the CORS options on the .NET side in Startup.cs and / or on the controller and put a break point in the controller code:
no error in IE 11 (however I get other TypeScript errors and can't debug due to the lack of .map files on Windows 7)
Chrome or FF don't hit the api at all, both return CORS errors (see below for errors):
When I disable all CORS settings on the api side:
no error in IE 11
Chrome and FF both hit the api and data are returned from my service. However "this.handleError" is always called and I get the CORS errors in the browser / TS code when the call returns:
====
Chrome error:
XMLHttpRequest cannot load http://localhost:13751/api/customer/2518. Response to preflight request doesn't pass access control check: A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://localhost:4200' is therefore not allowed access. The credentials mode of an XMLHttpRequest is controlled by the withCredentials attribute.
FF error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:13751/api/customer/2518. (Reason: CORS header 'Access-Control-Allow-Origin' missing)
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:13751/api/customer/2518. (Reason: CORS request failed).
====
So I really don't understand why I'm getting the CORS error in Chrome and FF when I can step through the code on the api side and data is returned to the client. (I also have the "Allow-Control-Allow-Origin" plugin for Chrome but this doesn't seem to make a difference).
Would be great if someone could shed some light on this.

Do you set the "Access-Control-Allow-Origin" header to the api response?
If not, here's a way of doing that:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors("MyPolicy");
// ... add api and other stuff
//Add a middleware which sets the header on the response
app.Use(async (context, next) =>
{
// Add Header
context.Response.Headers["Access-Control-Allow-Origin"] = "*";
// Call next middleware
await next.Invoke();
});
}

Cross origin requests are blocked by default because of the browser security policies. To allow CORS requests in Google Chrome install this plugin : https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?utm_source=chrome-ntp-icon
You will see an icon at top right corner of chrome. Turn on Cross origin resource sharing and then try it out.

Related

On Ionic 2, XMLHttpRequest cannot load .. with Laravel api

This is my scenario:
XMLHttpRequest cannot load http://phi.dev/api/login. Redirect from 'http://phi.dev/api/login' to 'http://localhost:8100/' has been blocked by CORS policy: Request requires preflight, which is disallowed to follow cross-origin redirect.
I have a Aungular2/Ionic 2 App on local and a Laravel Web API for authenticating user.
if I call this Web API from my Angular2 Module, I get an exception as given above.
Note: In Chrome Network, I could my angular service is being called 2 times. First with Request Method: OPTIONS and second time with Request Method: Get, which returns Http 302.
Does anyone know how to resolve this issue.
Thanks in advance.
Because the request is external and because you are serving the application locally you will have CORS issues.
To avoid such issues locally (when using ionic serve), you have to setup a local proxy in the ionic configuration files.
Check your Ionic 2 project directory and locate the file ionic.config.json: it usually is in the root directory of the project (and need to be there, along with package.json and so on).
Open the file, and add this (do not forget to be SURE that the line BEFORE that one ends with a comma (,), since it's a json file):
"proxies": [
{
"path": "/server",
"proxyUrl": "http://phi.dev"
}
]
Now, in the section where are you are performing the HTTP request, replace the http://phi.dev with /server. I will give you an example here.
I do recommend you, however, to be aware that such edit will make your compiled app to NOT work, so you likely want to put a debug flag for testing and compiled environments, like this:
class MyServiceOrComponent {
private debug: boolean = true; // Set this flag to FALSE when you need to actually compile the app for any real device.
private server: string = this.debug ? "/server" : "http://phi.dev";
constructor(private http: HTTP) {
const login = "/api/login"; // don't to it exactly like that, make a static list or something like this to store paths.
let request = this.http.get(this.server + login).then((res) => {
console.log(res);
});
}
}
What happens, explained briefly, is that if you perform the HTTP request as "localhost" it will throw you an exception (because of the CORS policy). Such will happen only when you are running the application in your testing environment (localhost). To avoid such, you provide a proxy, so that the request will be valid.

How to enable Cors in ASP.NET Web Api

I'm learning Angular 2. This is my service that's supposed to pull data from an ASP.NET Web api application.
#Injectable()
export class ExpenseService {
private _expUrl = "http://localhost:65400/api/expenses";
constructor(private _http: Http){}
getExpenses(): Observable<IExpense[]> {
return this._http.get(this._expUrl)
.map((response: Response) => <IExpense[]>response.json())
.do(data => console.log('ALL: ' + JSON.stringify(data)))
.catch(this.handleError)
}
//more here...
}
The above code is working fine in Microsoft Edge. However, in Chrome and FireFox, I'm getting the following error:
XMLHttpRequest cannot load http://localhost:65400/api/expenses.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:3000' is therefore not allowed
I've enabled CORS in my web api as suggested by many posts.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
//...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
//...
app.UseCors(builder =>
builder.WithOrigins("http://localhost:3000/"));
}
That didn't change the outcome. I'm still getting the same error in Chrome and FireFox while Edge is working just fine.
Thanks for helping
CORS is something that are enforced by the client, supported by the server.
CORS is there to help you as a user. It restrict the possibility for a client, like javascript on host google.com, to call a service on mydomain.com. This is a cross-domain call, which Chrome and FireFox does not allow. (Would assume that Edge also supported this). If you are hosting a service and client on some host and port, CORS is not used.
A service must define which host from a cross-domain is allowed. This can either be from all or from a specific host.
To allow access from all host do the following:
Configuration
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
Controller
[EnableCors("AllowSpecificOrigin")]
public class TestController : ApiController
If your service is a public service, be aware of the consequences.
You can read more here: https://learn.microsoft.com/en-us/aspnet/core/security/cors

Enabling CORS in Azure Service Fabric Web Api

I have an angular app that sends an http request to my Service Fabric Web API (deployed on a Secure Service Fabric cluster) like so:
$scope.request_headers = {
"Content-Type": "application/xml; charset=utf-8",
"Access-Control-Allow-Origin":"*"
}
$http({
url: "Service_Fabric_web_api_url",
method: "GET",
headers:$scope.request_headers
}).
then(function (result) {
console.log(result);
});
I've also enabled CORS globally in my web api startup class like so:
HttpConfiguration config = new HttpConfiguration();
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
When I run my angular app locally and try sending the http request, I still get this error:
XMLHttpRequest cannot load Service_Fabric_web_api_url. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:xxxxx' is therefore not allowed access. The response had HTTP status code 500.
I'm able to access my service directly from my browser with the same url.
Also, the same http request works when I tried deploying my Web Api on an unsecure Service Fabric Cluster with the same lines added to the startup class to enable CORS.
Why is this happening even though I've enabled CORS globally in my Web API and particularly when its on a secure cluster?
In your Startup.cs class, do you have this line? :
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
}
There are also a couple NuGet packages associated with Cors:
<package id="Microsoft.AspNet.Cors" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.Owin.Cors" version="3.0.1" targetFramework="net45" />
The CORS message is a red herring. If you look at the end of the error message you'll see this:
The response had HTTP status code 500.
Usually the response will include some detail about the error. I suggest using a tool like Fiddler with HTTPS decryption enabled so you can see the content of the response.

CORS works for access token but not for refresh token in Web Api 2

I have a web api 2 app which I call to using an angularjs client. The web api app is capable of issuing access tokens and refresh tokens for authentication.
Having the following lines in the "GrantResourceOwnersCredentials" method, the CORS is working fine for allowing to issue access tokens:
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
if (allowedOrigin == null) allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
However, when I try to issue refresh tokens through the angularjs app, I get this good old error in the console:
OPTIONS http://localhost:65141/token
(index):1 XMLHttpRequest cannot load http://localhost:65141/token. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:56815' is therefore not allowed access. The response had HTTP status code 400.
I was wondering as the access tokens are being issued fine, and the refresh tokens are also issued using the same endpoint, what should I do to overcome this issue?
By the way, the angular code is fine. I disabled google chrome web security and then everything worked! Any help is greatly appreciated!
After searching the whole freaking internet, here is what I found that resolves the problem. Adding this code to the AuthorizationProvider will resolve the problem:
public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
if (context.IsTokenEndpoint && context.Request.Method == "OPTIONS")
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "authorization" });
context.RequestCompleted();
return Task.FromResult(0);
}
return base.MatchEndpoint(context);
}

CHROME showing http response as cancelled

Using Chrome developer tools.I am getting a cancelled status on a request to a WEB API resource.(network tab)
Server : WEB API 2.1
Client: Angular $http request
The initial message referred to a CORS violation as the cause. I enabled CORS on the server.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//Going camel case in Web API http://frankapi.wordpress.com/2012/09/09/going-camelcase-in-asp-net-mvc-web-api/
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
// cors support
var cors = new EnableCorsAttribute( "http://localhost:9168/", "*", "*");
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable<T> return type.
// To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries.
// For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712.
//config.EnableQuerySupport();
}
}
After CORS was implemented, I am still getting cancelled a response message on the API calls, however, when drilling into the message, the data is being returned from the server.
I checked Fiddler and the request header is passing the origin etc correctly, however I am still getting this error:
XMLHttpRequest cannot load http://localhost:4416/api/LookupTrades. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9168' is therefore not allowed access.
There seems to be loads of posts about the cancelled status in chrome, all with different causes. Not sure what to do next. Any ideas?
install a Nuget package `"Microsoft.AspNet.WebApi.Cors" (version="5.1.0")
Add following line in your WebApiConfig.cs file
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
you can also set this property in your js file before ajax call
$.support.cors = true;

Resources