39

I can see that there is an option in HubConnection to pass parameters through url request from client. Is there any way to pass specific token through http headers from JS or .NET clients?

Eduard Truuvaart
  • 419
  • 1
  • 4
  • 8

6 Answers6

57

There is no easy way to set HTTP headers for SignalR requests using the JS or .NET client, but you can add parameters to the query string that will be sent as part of each SignalR request:

JS Client

$.connection.hub.qs = { "token" : tokenValue };
$.connection.hub.start().done(function() { /* ... */ });

.NET Client

var connection = new HubConnection("http://foo/",
                                   new Dictionary<string, string>
                                   {
                                       { "token", tokenValue }
                                   });

Inside a Hub you can access the community name through the Context:

Context.QueryString["token"]

You can add to the query string when making persistent connections as well.

EDIT: It is now possible to set headers on the .NET SignalR client as pointed out by some of the commenters.

Setting Headers on the .NET Client

var connection = new HubConnection("http://foo/");
connection.Headers.Add("token", tokenValue);
halter73
  • 14,442
  • 3
  • 44
  • 54
  • Thanks! Yes, it seems to be the only way at the moment to pass additional params to connection. – Eduard Truuvaart Mar 21 '13 at 10:00
  • 5
    The latest version of SignalR 1.1.0beta supports setting headers. You can get the latest packages from NuGet. – Abhishek Nanda Apr 12 '13 at 00:11
  • I can't seem to find any documentation of how to actually set the header. Could you point me in some direction? – Are Almaas May 27 '13 at 13:14
  • 1
    HubConnection has a Headers dictionary. You can add to that dictionary but you need to add the headers before you start the connection. – Abhishek Nanda May 28 '13 at 18:28
  • @halter73 is it safe to pass userid and username parameters in this way ? Can another use this parameters disconnect the connected users ? – Freshblood Dec 09 '13 at 01:28
  • @Freshblood You have to treat query string parameters like any other user input, i.e. don't trust it. You can use HMAC to verify that the parameter was generated on the server and SSL to prevent MitM attacks. It is already possible to access the client's authenticated connection id inside of a Hub method: http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-server#contextproperty You can only stop a SignalR connection from the client, but you can always create a client-side hub method that stops the connection and can be invoked by the server. – halter73 Dec 09 '13 at 07:39
  • You can with hubConnection.Headers.Add("myCustomHeader", "myvalue"); with Microsoft.AspNet.SignalR.Client 2.0.3.0 in WinRT XAML app. – MemeDeveloper Jun 04 '14 at 21:45
  • @Thomas I'm not sure what you mean by hacky. SignalR puts various tokens that it uses (e.g. the `connectionToken` and `groupsToken`) in the query string of each SignalR request. I don't see why this would be a problem for most applications. Is it a problem because query strings often show up in logs? Or due to URL length limits? For some types of requests, like WebSocket requests made using the JS WebSocket API, so using HTTP headers just isn't an option. – halter73 Jan 14 '15 at 20:14
  • @halter73 What is the proper solution to actually authorize a hub method based on tokens? Here's what I do: I have a custom `AuthorizeAttribute` that retireves the token. Now the probem is that I don't seem to be able to unprotect it and get the information. Is this the way to go? – radu-matei Sep 03 '15 at 12:21
  • @Matei_Radu If you want to use the same auth logic for all your hubs, you can use a global module. This blog post might be helpful to you: http://geekswithblogs.net/shaunxu/archive/2014/05/27/set-context-user-principal-for-customized-authentication-in-signalr.aspx – halter73 Sep 08 '15 at 19:04
16

You can add headers on either Connection or HubConnection using the .NET client (as @abnanda mentions):

var connection = new Connection("http://signalr/");
connection.Headers.Add("custom-header", "value");

On the server side you can retrieve the header value from IRequest in e.g. OnConnected:

var header = request.Headers["custom-header"];

However, I have not yet found a way to do this with the JS client (there is no headers or addHeaders on the $connection object).

I have posted a question on that at: http://forums.asp.net/t/1910020.aspx/1?Add+custom+HTTP+header+on+client+side+connect+call+SignalR+1+1+1+

EDIT: The headers are not exposed since the websocket client (in browser) does not support it (so it would not be possible to implement it across transports). See David Fowlers response in the post above.

cwt237
  • 257
  • 3
  • 9
4

I solved this by adding my information to the querystring, which is available on the IConnected.Connect() method.

On the .NET client you pass the querystring into your HubConnection:

var connection = new HubConnection("http://localhost:8080/", "myInfo=12345");

On the JS client you set the qs property before starting the connection:

$.connection.hub.qs = "myInfo=12345";

You can then access this information on the server in the Connect() method:

var myInfo = Context.QueryString["myInfo"];
Groups.Add(Context.ConnectionId, myInfo);
Mou
  • 13,749
  • 38
  • 131
  • 248
  • But how to solve problem with access_token expiration. Their lifetime usually about 5 minutes, then you will get 401 response – dantey89 Jan 30 '19 at 19:56
3

With the js client, I don't think the header is supported but it must go via the querysting instead.

For the javascript client that is not the generated js proxy, you can add extra information to the querystring like this:

var connection = $.hubConnection("http://localhost:3306/signalr");
connection.qs = "somekey=somevalue";
var hubProxy = connection.createHubProxy('hubname');

Messages such as ping, negotiate, abort, connect will now include this querystring value.

It's possible to send the header if you affect the ajax global setup. I have observed it making to the server but have not tested that it makes it in every case you might need.

  $.ajaxSetup({
      beforeSend: function (xhr)
      {
         xhr.setRequestHeader("Authorization","Token token=\"abcdef\"");        
      }
  });
CRice
  • 11,533
  • 7
  • 52
  • 80
3

Hello guys this is the best approach for a .Net Client!

In my client added the Authorization header to the HubConnectionBuilder like this:

For Bearer Token ->

HubConnection = new HubConnectionBuilder()
            .WithUrl($"https://10.0.2.2:5001/chatHub", (opts) =>
            {                    
                opts.Headers.Add("Authorization", new AuthenticationHeaderValue(
                        "Bearer", "YOUR_TOKEN").ToString());                    
            })                
            .Build();

You can also use Basic token like this ->

HubConnection = new HubConnectionBuilder()
            .WithUrl($"https://10.0.2.2:5001/chatHub", (opts) =>
            {                    
                opts.Headers.Add("Authorization", new AuthenticationHeaderValue(
                        "Basic", Convert.ToBase64String(
                            Encoding.Default.GetBytes(
                                "Username" + ":" + "Password"
                                ))).ToString());                    
            })                
            .Build();
MarchalPT
  • 368
  • 1
  • 11
1
using Microsoft.AspNet.SignalR.Client;

HubConnection = new HubConnection(_url);
HubProxy = HubConnection.CreateHubProxy(_hubname);
HubConnection.Headers.Add("Authorization", "Bearer "+authToken);
HubConnection .Start().Wait();
Nick Kovalsky
  • 3,015
  • 15
  • 35