ng2-signalr icon indicating copy to clipboard operation
ng2-signalr copied to clipboard

How to set Authorization Header ?

Open Usman235 opened this issue 7 years ago • 9 comments

I am using ng2-signalrin ionic 2. Issue is that i don't know how to set authorization header. I have search but didn't find any example.

My code for connecting to server hub.

   let options: IConnectionOptions = { qs:{userId:1}, url: "http://192.168.0.211:44337"};
                
		console.log("Stage 1");
			//Header for 'this.singalR.connect'
        this.signalR.connect(options)
            .then((connection) => {                      
        
                console.log("Client Id: " + connection.id);                     
             }, (err) => {
                console.log("SignalR Error: " + JSON.stringify(err));
            });
       

How to set below header ?

  var headers = new Headers({
            'Content-Type': "application/json",
            "Authorization": 'Bearer ' + accessToken  //accessToken contain bearer value.
        });

Note: Before implementing Authorization same code working fine as i don't need to set authorization header.

Usman235 avatar May 31 '17 07:05 Usman235

you need to send the token as a query parameter instead of qs:{userId:1} write qs:{userId:1, token: 'your token'}

HNeukermans avatar May 31 '17 10:05 HNeukermans

@HNeukermans Thanks for response.

Issue it that is have two signalr client , one is in simple angularjs and other is ionic 2 .

In Simple Angularjs i'm doing following to set the header. (Which is working).

$.signalR.ajaxDefaults.headers = new Headers({
            'Content-Type': "application/json",
            "Authorization": 'Bearer ' + accessToken  //accessToken contain bearer value.
        });

I'm wondering if there is way to send headers just like above . If i go for query string option that is what you suggested then i have to change a lot of code on server side as well as on simple angularjs signalr client .

Is there any other way ?

Usman235 avatar May 31 '17 11:05 Usman235

Hi @Usman235,,

thx a ton. I didn't even know this existed inside signalr. Sorry, my fault... Seems like a next ng2-signalr super feature !! As a workaround inside your typescript project you can always do

declare var $: any;
$.signalR.ajaxDefaults.headers = new Headers({
            'Content-Type': "application/json",
            "Authorization": 'Bearer ' + accessToken  //accessToken contain bearer value.
        }); 

If you feel comfortable writing typescript,.. Would you like to try to add the feature to ng2-signalr yourself ?

From my part, I will add this feature, the moment I find some free time...

Maybe a small question to you about the ajaxDefaults? The headers you add there: Are these send with every signalr request you do? If you change the ajaxDefaults headers when you already have an ongong connection,are the changes taken into account ? Or do you need to create a newly instantiated connection for that ?

HNeukermans avatar Jun 01 '17 06:06 HNeukermans

@HNeukermans sorry for late response.

I'm beginner to typescript . :)

The headers you add there: Are these send with every signalr request you do?

Yes headers are send with every signalr request.

If you change the ajaxDefaults headers when you already have an ongong connection,are the changes taken into account ? Or do you need to create a newly instantiated connection for that ?

Yes if i change ajaxDefaults headers changes are automatically applied i don't need to newly instantiated connection.

Unfortunately below didn't work for me.

declare var $: any;
$.signalR.ajaxDefaults.headers = new Headers({
            'Content-Type': "application/json",
            "Authorization": 'Bearer ' + accessToken  //accessToken contain bearer value.
        });

As i have to meet deadline so i implemented qs method which you suggested me . And at server side added a new middlerware which check for every request if token is in query string simple it just add that token in request header.

Usman235 avatar Jun 08 '17 08:06 Usman235

Found a solution. You need to use the window object to get access to jQuery, you just have to cast it to an any.

    let $ = (<any>window).$;
    $.signalR.ajaxDefaults.headers = {
      'Content-Type': "application/json",
      "Authorization": 'Bearer ' + this.oauthService.getAccessToken()
    };

Jrubzjeknf avatar Jun 16 '17 14:06 Jrubzjeknf

How does the real-life implementation look like? I having issues with injecting my oauthService there... Are you putting it into the createConfig(): SignalRConfiguration ?

mcgri avatar Nov 30 '17 13:11 mcgri

We created a custom service where the SignalR and OAuthService are injected. Below is a basic example where the ISignalRConnection is provided through an Observable. This way, if the connection is interrupted and re-establised, you are able to automatically resubscribe to the new connection.

import { Injectable, OnInit } from '@angular/core';
import { SignalR, ISignalRConnection } from 'ng2-signalr';
import { Notice } from "app/feed/notice/notice.model";
import { Observable } from "rxjs/Observable";
import { Subject } from "rxjs/Subject";
import { OAuthService } from "angular-oauth2-oidc/dist";

@Injectable()
export class SignalrService {
  private subject: Subject<ISignalRConnection>;
  public connection: Observable<ISignalRConnection>;

  constructor(private signalR: SignalR, private oauthService: OAuthService) {
    this.subject = new Subject<ISignalRConnection>();
    this.connection = this.subject.asObservable().shareReplay(1);

    if (navigator.onLine) {
      this.connect();
    }
  }

  private connect() {
    // Set auth headers.
    let $ = (<any>window).$;
    $.signalR.ajaxDefaults.headers = {
      'Content-Type': "application/json",
      "Authorization": 'Bearer ' + this.oauthService.getAccessToken()
    };

    let promise = this.signalR.connect();

    promise
      .then(x => {
        this.subject.next(x);

        x.errors.subscribe(y => {
          if (y.message.includes(`Couldn't reconnect within the configured timeout`)) {
            this.reconnect();
          }
        })
      })
      .catch(x => this.reconnect());
  }

  private reconnect() {
    let ms = 3000;
    console.log(`Manual reconnect after ${ms}ms`);
    setTimeout(() => this.connect(), ms)
  }
}

And to listen for a message, inject this SignalrService and subscribe to the connection Observable:

    this.signalrService
        .connection
        .subscribe(connection => connection
            .listenFor('your-message')
            .subscribe((yourMessage: IYourMessage) => {
                // do something
            }));

Jrubzjeknf avatar Nov 30 '17 14:11 Jrubzjeknf

from jquery.signalR.core.js: // With sse or ws, access_token in request header is not supported if (connection.transport && connection.accessToken) { if (connection.transport.name === "serverSentEvents" || connection.transport.name === "webSockets") { url += "&access_token=" + window.encodeURIComponent(connection.accessToken); } }

rely on $.signalR.ajaxDefaults.headers will only enable longPolling, but sse or ws negotiate request will return 401, I think relying on query params is better.

IbrahimElkhatib avatar Jan 12 '22 07:01 IbrahimElkhatib

Hello,

Is it already possible to send an Authorization header something like this:

(headers: request.headers.set('Authorization', 'Bearer ' + token) <-- using a JWT token here.

instead of via query string parameters?

In my angular app i use an interceptor where i add a header to all my http requests. I did not test it yet but maybe if i try it with an interceptor it could work? this week i will try that and let you know... fingers crossed :)

Edit: Maybe this will help if we are bound to query string parameters. -> https://stackoverflow.com/a/57460785

Prefix1802 avatar May 08 '23 10:05 Prefix1802