Reputation: 1391
I know there are a lot of questions and answeres regarding this topic out there, but nothing matched my specific issue.
I am using the following versions
VERSION UPDATE:
The SignalR connection works pretty fine until I add an accessTokenFactory in the Angular frontend.
Frontend
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(`${environment.bzApiBaseUrl}/hubs/heartbeat`, {
accessTokenFactory: () => token
})
.build();
this.hubConnection
.start()
.then(() => {
console.log('SignalR: Heartbeat - connection started');
this.hubConnection.on('beat', () => {
console.log('SignalR: Heartbeat - Heartbeat received');
});
})
.catch(err => console.log('SignalR: Heartbeat - error while starting connection: ' + err));
});
The connection gets established when I remove the accessTokenFactory
from HubConnectionBuilder
.
Backend
services.AddCors(options =>
{
options.AddPolicy(
name: MyAllowSpecificOrigins,
builder =>
{
builder
.WithOrigins(CorsSettings.TargetDomain)
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials();
});
});
The value of the CorsSetting domain is http://localhost:4200
where the frontend is running.
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(e =>
{
e.MapControllers();
e.MapHub<HeartbeatHub>("/api/hubs/heartbeat");
});
The following error gets logged in browsers console after adding accessTokenFactory
:
WebSocketTransport.js:70
WebSocket connection to 'ws://localhost:33258/api/hubs/heartbeat?id=BpBytwkEatklNR-XqGtabA&access_token=eyJ0eXAiOiJKV1QiLCJhbGci... failed:
Utils.js:190
Error: Failed to start the transport 'WebSockets': undefined
dashboard:1
Access to resource at 'http://localhost:33258/api/hubs/heartbeat?id=iWuMeeOKkWCUa8X9z7jXyA&access_token=eyJ0eXAiOiJKV1QiLCJhbGci...' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I don't understand the CORS issue due to the fact that it seems to be raised by adding a token to the query string with the accessTokenFactory.
I tried:
UPDATE
The connection gets established when setting the HttpTransportType
to LongPolling
. It does not work with WebSockets
or ServerSentEvents
.
app.UseEndpoints(e =>
{
e.MapControllers();
e.MapHub<HeartbeatHub>("/api/hubs/heartbeat", options =>
{
options.Transports = HttpTransportType.LongPolling;
});
});
It seems as the token gets send as an HTTP header instead of a query string parameter when using long polling. The token is very long, so I break through the max. allowed URL length when using WebSockets or ServerSentEvents. But I have still no idea why this leads to a CORS exception.
Upvotes: 4
Views: 1141
Reputation: 1391
Browsers do not support headers for websockets, therefore the bearer token has to be added as query string parameter. We hit the maximum length for URLs due to the length of our bearer token. We could shorten our token or use a reference token, see also: https://github.com/aspnet/SignalR/issues/1266
Hope this helps others as well.
Upvotes: 3