ASP.NET SignalR - 401 Unauthorized - JWT Authorization

Viewed 551

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:

enter image description here

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": enter image description here

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?

0 Answers
Related