I'm trying to implement SignalR support in an ASP.NET / Angular App, but I'm having difficulties with the JWT-Authentication.
First I'm appending the token in the appropriate request, which can be seen in the server code down below. This seems to work fine, but I always get HTTP error 401 (Unauthorized) when trying to establish the websocket connection. When hitting a breakpoint in the code above, I can see that the token is assigned correctly:
All the other HTTP endpoints have the [Authorize] annotation, where the User object is accessible as excepted.
Here's a screenshot of the HTTP traffic. It's the same bearer token that works for all the other endpoints, but here it says "invalid token":

The server uses the Microsoft.AspNetCore.SignalR package, Version 1.1.0
Angular Client uses "@microsoft/signalr": "^5.0.7"
Here's the client code where the token is added when establishing the connection:
public startConnection = () => {
const options: IHttpConnectionOptions = {
accessTokenFactory: () => {
return this._settings.authorization?.access_token;
}
};
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl('http://localhost:8990/apphub', options)
.build();
this.hubConnection
.start()
.then(() => console.log('Connection started'))
.catch(err => console.log('Error while starting connection: ' + err))
}
This is the startup code to add JWT authentication:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Events = new JwtBearerEvents
{
OnTokenValidated = ctx =>
{
Log.Logger.Information("Authentication - Token validated.");
return Task.CompletedTask;
},
OnMessageReceived = ctx =>
{
Log.Logger.Information("Authentication - Message received.");
var tokenInQuery = ctx.Request.Query.TryGetValue("authorization", out var queryToken);
var tokenInHeader = ctx.Request.Headers.TryGetValue("authorization", out var headerToken);
if (tokenInQuery || tokenInHeader)
{
var path = ctx.HttpContext.Request.Path;
if (path.StartsWithSegments("/apphub", StringComparison.OrdinalIgnoreCase))
{
if(!string.IsNullOrEmpty(queryToken))
{
ctx.Token = queryToken;
}
else if(!string.IsNullOrEmpty(headerToken))
{
ctx.Token = headerToken;
}
}
}
return Task.CompletedTask;
},
OnAuthenticationFailed = ctx =>
{
Log.Logger.Information("Authentication - Authentication failed.");
return Task.CompletedTask;
}
};
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["SecurityKeyIssuer"],
ValidAudience = Configuration["SecurityKeyAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SecurityKey"]))
};
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddMemoryCache();
// services.AddCors();
services.AddCors(o => o.AddPolicy("AllowAnyOrigin", builder =>
{
builder.WithOrigins("http://locahost:4000")
//.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed((x) => true)
.AllowCredentials();
}));
Any ideas?
