'Can't get username with SignalR and jwt token

Trying to learn SignalR and netcore kinda both at the same time and I am trying to get the username of the logged in user based on its jwt token.

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
 {
      options.Authority = "https://localhost:7005/"; 
      options.Events = new JwtBearerEvents
      {
      OnMessageReceived = context =>
      {
          var accessToken = context.Request.Query["access_token"];

          var path = context.HttpContext.Request.Path;
          if (!string.IsNullOrEmpty(accessToken) &&
              (path.StartsWithSegments("/chathub/negotiate")))
          {
              try
                {
                    var tokenHandler = new JwtSecurityTokenHandler();
                    var key = Encoding.ASCII.GetBytes(builder.Configuration.GetValue<string>("AppSettings:Secret"));
                    tokenHandler.ValidateToken(accessToken, new TokenValidationParameters
                    {
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(key),
                        ValidateIssuer = false,
                        ValidateAudience = false,
                        ClockSkew = TimeSpan.Zero
                    }, out SecurityToken validatedToken);

                    var jwtToken = (JwtSecurityToken)validatedToken;
                    var username = int.Parse(jwtToken.Claims.First(x => x.Type == "unique_name").Value);

                    context.HttpContext.Items["username"] = username;
                    context.HttpContext.Items["token"] = accessToken;
                }
                catch
                {
                }
          }
          return Task.CompletedTask;
      }
  };
 });

And Hub method is:

public override async Task OnConnectedAsync()
{
    var username = Context.GetHttpContext().Items["username"];      

    _connections.Add("bob", Context.ConnectionId);

    await Clients.All.SendAsync("UpdateConnectionsList", _connections.GetConnections("bob"));
}

So username is null when I start the connection. What I don't understand here, is when I added the options to Authentication service my breakpoints would go inside there, now it just skips this code and I don't understand whats wrong.

Or am I doing it all wrong? When OnConnectedAsync happens is not after options.Events like above?

This is the angular code

  private startConnection() {
    const url = 'https://localhost:7005/chathub';
    const token = localStorage.getItem('token')?.toString()!;

    this.hubConnection = new HubConnectionBuilder()
    .withUrl(`${url}?access_token=${token}`)
      .build();

      this.hubConnection
      .start()
      .then(() => {
          console.log('Connection started!');
      }) 
      .catch((err:any) => console.log('Error while establishing connection :('));

      this.hubConnection.on('UpdateConnectionsList', (connections) => {
        this.connections = connections;
      });

      this.hubConnection.on('SendMessage', (nick: string, receivedMessage: string) => {
        const text = `${nick}: ${receivedMessage}`;
        this.messages.push(text);
      });
  }

Thank you for your time and help

Edit: I solved the issue and after breaking the step in button there were multiple problems:

  1. int.Parse thing, I think I tried random things and I didn't took that line in the account anymore.
  2. not throwing a proper exception in the catch or having a global exception handling
  3. path.StartsWithSegments("/chathub/negotiate") is just chathub since I get two requests and I don't actually care about negotiate(I think, maybe thats a hook where I can do something else, I don't know what), this is why this code got skipped since second request is about what I want not about negotiation with the server


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source