Hi! I just upgraded from ASP.NET Core 2.1.6 to 2.2.0, everything working just fine except my connections to SignalR. In the negotiation phase (using javascript client and over websocket) I get a 204 with the error
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ‘https://localhost:44333/ChatHub/negotiate’. (Reason: Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’).
Taking a look at the request I have the following
So the server sends out a '*' instead of just sending out the origin from which the request came. The app needs to allow all origins since our users can add a chat to their own site.
In my Startup.cs I have defined CORS rules as follows
services.AddCors(options =>
{
options.AddPolicy("AllowAllOrigins", b =>
{
b.AllowAnyOrigin()
.AllowCredentials()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
Mind that this was working on 2.1.6 and earlier versions.
In the client side code I can get the chat to work if I set skipNegotiation to true, like this
connection = new signalR.HubConnectionBuilder()
.withUrl(serverURL + "ChatHub", { skipNegotiation: true, transport: signalR.HttpTransportType.WebSockets })
.build();
But I'm guessing that will have it's own consequences and is not solving the real problem.
Been reading through so many threads and I just can't get this to work again, anyone have any ideas as to might be causing it?
Steps to reproduce the behavior:
To not recieve the CORS error, instead have the server return the allowed origin as a URL instead of wildcard '*' since this won't work with credentials, which is needed for SignalR as I understand it (for sticky cookies)
Also, since setting skipNegotiation
to true
"solves" the problem, what does that actually do? With it set to true chatting works fine - does that mean the CORS settings are working overall, but just not for the negotiation part?
skipNegotiation
will skip the HTTP negotiate that does transport fallback and will only run WebSockets. WebSockets and CORS are not compatible so you end up skipping CORS when using that.
As far as your actual problem, in 2.2 AllowAnyOrigin
+ AllowCredentials
now fails on purpose because it is insecure and I believe not allowed by the CORS spec. You need to explicitly specify your allowed origins.
Thank you @BrennanConroy
That's quite bad news then since SignalR requires credentials by default and my app has lots of users with lots of different origins they are calling my app from. Do you have any suggestion for what would be a good solution for this, can the credentials requirements for SignalR be disabled for example (and then removed from my Startup.cs)?
Adding all origins separately is unfortunately not an option as I see it with how our app is working.
EDIT: Oh and also, been searching, but are there any updated documentation regarding these changes for CORS available?
@pranavkm For docs.
Currently your CORS does nothing (allows everything), so you could just disable it by writing a custom middleware that returns the "correct" response to the browser.
I am curious what your scenario is that causes you to host the browser client from many different origins.
so you could just disable it by writing a custom middleware that returns the "correct" response to the browser.
Hmm, OK - can't say I have any deeper knowledge on how to do that but thanks I'll start reading up on how to do it!
I am curious what your scenario is that causes you to host the browser client from many different origins.
The app offers users to place chat widgets on their sites, it's a SaaS so users can then over at our app chat with users on their site 😃
@pranavkm For docs.
Currently your CORS does nothing (allows everything), so you could just disable it by writing a custom middleware that returns the "correct" response to the browser.
An update regarding this. Thank you so much for sending me the right way! I implemented a custom CORS middleware and now everything is working just as before. For reference is anyone else stumbles upon the same problem: https://stackoverflow.com/questions/44379560/how-to-enable-cors-in-asp-net-core-webapi
@pranavkm For docs.
Currently your CORS does nothing (allows everything), so you could just disable it by writing a custom middleware that returns the "correct" response to the browser.An update regarding this. Thank you so much for sending me the right way! I implemented a custom CORS middleware and now everything is working just as before. For reference is anyone else stumbles upon the same problem: https://stackoverflow.com/questions/44379560/how-to-enable-cors-in-asp-net-core-webapi
@rr222cy What did you write in your CORS middleware? I haven't been able to solve this issue.
Will there be a fix?
@solojuve1897, @endeffects, I solved the problem through Middleware.
CorsMiddleware.cs
public class CorsMiddleware
{
private readonly RequestDelegate _next;
public CorsMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext)
{
if (httpContext.Request.Headers.TryGetValue("Origin", out var originValue))
{
httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
httpContext.Response.Headers.Add("Access-Control-Allow-Headers", "x-requested-with");
httpContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
httpContext.Response.Headers.Add("Access-Control-Allow-Origin", originValue);
if (httpContext.Request.Method == "OPTIONS")
{
httpContext.Response.StatusCode = 204;
return httpContext.Response.WriteAsync(string.Empty);
}
}
return _next(httpContext);
}
}
public static class CorsMiddlewareExtensions
{
public static IApplicationBuilder UseCorsMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CorsMiddleware>();
}
}
Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCorsMiddleware();
...........
@cores-system
Thanx for the answer. What I ended up doing was the following:
In ConfigureServices-method:
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials();
}));
In Configure-method:
app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
{
routes.MapHub<General>("/hubs/general");
});
Most helpful comment
@cores-system
Thanx for the answer. What I ended up doing was the following:
In ConfigureServices-method:
In Configure-method: