0
votes

I am building an application using

Angular 4

AspNetCore 2

AspNetCore.SignalR 1.0.0-alpha2-final

and JWT Authentication

My issue is this. I cannot seem to authenticate the user on the hub level

i have a require claim policy that works on all of my controllers

 services.AddAuthorization(options =>
            {
              options.AddPolicy("ApiUser", policy => 
              policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, 
              Constants.Strings.JwtClaims.ApiAccess));
            });

and in the controllers i do

[Authorize(Policy = "ApiUser")]

this all works great. however as many of you may know you are not allowed to add authorization headers to websockets from javascript, and so the solution provided by the talented contributors over at https://github.com/aspnet/SignalR is to pass the JWT token as a query string.

this however is eluding me a bit. here is my auth config in startup.cs

services.Configure<JwtIssuerOptions>(options =>
            {
                options.Issuer = 
                jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
                options.Audience = 
                jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
                options.SigningCredentials = new 
                SigningCredentials(_signingKey, 
                SecurityAlgorithms.HmacSha256);
            });

            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer = 
                jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],

                ValidateAudience = true,
                ValidAudience = 
                jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],

                ValidateIssuerSigningKey = true,
                IssuerSigningKey = _signingKey,

                RequireExpirationTime = false,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            };
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = 
                JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = 
                JwtBearerDefaults.AuthenticationScheme;

            }).AddJwtBearer(configureOptions =>
            {
                configureOptions.ClaimsIssuer = 
                jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
                configureOptions.TokenValidationParameters = 
                tokenValidationParameters;
                configureOptions.SaveToken = true;


                configureOptions.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var signalRTokenHeader = 
                        context.Request.Query["signalRTokenHeader"];
                        if (!string.IsNullOrEmpty(signalRTokenHeader) &&

                       (context.HttpContext.WebSockets.IsWebSocketRequest ||                                        
                  context.Request.Headers["Accept"] == "text/event-stream"))
                        {
                            context.Token = 
                            context.Request.Query["signalRTokenHeader"];
                        }
                        return Task.CompletedTask;
                     }
                 };
            });

now here is the client code (typescript)

ngOnInit() {
let authToken = localStorage.getItem('auth_token');

    this.options = {
        transport: TransportType.WebSockets,
        authToken: authToken
    };

    this._hubConnection = new HubConnection('http://localhost:51143/chat', 
    this.options);
    this._hubConnection
        .start()
        .then(() => console.log('Connection started!'))            
       .catch(err => console.log('Error while establishing connection :('));

The goal here is to pass my authtoken to the signalR hub like this (same way i do on my api controller which works great)

[Authorize(Policy = "ApiUser")]
public class ChatHub : HubWithPresence

so that i am able to hydrate the User.Identity within the HubConnection Context

 Clients.All.InvokeAsync("sendToAll", Context.User.Identity.Name, 
receivedMessage);

any help here would be greatly appreciated! been stuck for a few days, this is the last missing piece to really get these things working together.

1

1 Answers

2
votes

I see you're using 1.0.0-alpha2. Unfortunately there is no JWT support in the TypeScript client in 1.0.0-alpha2. To use JWT you need to use nightly builds of the upcoming preview1 client. See https://github.com/aspnet/SignalR#packages for more details.