SignalR + Angular: how to add Bearer token to Http Headers

André Luiz picture André Luiz · Jan 5, 2018 · Viewed 11.6k times · Source

I made an asp.net core 2.0 SignalR Hub which uses Bearer Token for Authentication. Now I'm a bit lost on how to connect to it via the SignalR Angular 5 client. I actually can connect if I remove authorization from the Hub, so the connection is working, now I believe I just need to add the Authorization Bearer to the Http Headers of the connection.

The SignalR client reference in the package.json file of my Angular 5 project: "@aspnet/signalr-client": "^1.0.0-alpha2-final"

My Angular component:

import { Component, OnInit } from '@angular/core';
import { finalize } from 'rxjs/operators';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { ToastrService } from 'ngx-toastr';
import { AuthenticationService } from '../core/authentication/authentication.service';
import { HubConnection } from '@aspnet/signalr-client';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {

  quote: string;
  isLoading: boolean;
  jwtToken:string;
  private hubConnection: HubConnection;

  constructor(
    private _http: HttpClient, 
    private _auth : AuthenticationService,
    private _toastr: ToastrService) { }

  ngOnInit() {
    this.isLoading = false;
    this.jwtToken = this._auth.currentToken;

    this.hubConnection = new HubConnection('http://localhost:27081/hub/notification/');
    this.hubConnection
      .start()
      .then(() => console.log('Connection started!'))
     .catch(err => console.error('Error while establishing connection :(', err));        
    this.hubConnection.on("send", data => {
        console.log(data);
    });
  }

  showToastr(){
    this._toastr.success('Hello world!', 'Toastr fun!');
  }

}

Due to reading similar questions I tried: this.hubConnection.Headers.Add("token", tokenValue); but it doesn't work, the Headers property doesn't exist.

How can I add the Bearer token to the Http Headers of the HubConnection?

Thanks for any help

Answer

Darryn Hosking picture Darryn Hosking · Aug 12, 2019

To do this with @aspnet/signalr (^1.1.4) you can use the following code

const options: IHttpConnectionOptions = {
  accessTokenFactory: () => {
    return "Token is resolved here";
  }
};

const connection = new signalR.HubConnectionBuilder()
  .configureLogging(signalR.LogLevel.Information)
  .withUrl(`${environment.apiUrl}/notify`, options)
  .build();

Also add an annotation to your Hub

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

As a side note, SignalR when using the websocket protocol does not seem to attach the Bearer token as a header and instead adds it to the request URL as an 'access_token' parameter, this requires you to configure your authentication to handle this token when signalR chooses to use ws.

services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
                x.Events= new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var accessToken = context.Request.Query["access_token"];

                        // If the request is for our hub...
                        var path = context.HttpContext.Request.Path;
                        if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/notify")))
                        {
                            // Read the token out of the query string
                            context.Token = accessToken;
                        }
                        return Task.CompletedTask;
                    }
                };
            });