I am developing a prototype of an AngularJS, Web API, SignalR application as a potential starting point for a new project in VS 2013.
At this stage, I'm pretty much using the canned code that visual studio generates for Individual User Accounts.
There's a line in the StartUp.Auth.cs code that looks like this.
app.UseOAuthBearerTokens(OAuthOptions);
With this in place, I can add the [Authorize] attribute to controllers and it works fine.
Incidentally, with angular I was able to add a standard header containing the token in the JavaScript as follows.
$http.defaults.headers.common.Authorization = 'bearer ' + access_token;
Then I added SignalR to the project.
It supports it's own version of the [Authorize] attribute but there is no way to pass custom headers when using SignalR.
It's a limitation on the browser side.
The documentation said you could pass the token as part of the query string.
I added that code on the JavaScript side. My SignalR code now included this.
I passed the token as 'bearer_token'.
this.connection = $.hubConnection("/TestHub", { useDefaultPath: false, qs: "bearer_token=" + token });
So my issue was how to make OWIN recognize the token now it was no longer in the header.
After a number of searches, I ended up adding code that moved the token from the querystring into the header.
For my prototype, I just added a little code above the original line in StartUp.Auth.cs.
So, now it looked like this:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions() { Provider = new OAuthBearerAuthenticationProvider() { OnRequestToken = context => { if (context.Request.Path.Value.StartsWith("/TestHub")) { string bearerToken = context.Request.Query.Get("bearer_token"); if (bearerToken != null) { string[] authorization = new string[] { "bearer " + bearerToken }; context.Request.Headers.Add("Authorization", authorization); } } return Task.FromResult(context); } } }); // Enable the application to use bearer tokens to authenticate users app.UseOAuthBearerTokens(OAuthOptions);
The code above is rough but this is a prototype so really I just wanted to see if it worked which it did.
Finally getting to the question: Is this the right pattern for integrating bearer token authorization with SignalR and the OWIN pipeline.
I couldn't seem to find much good information on the right way to do this.
Objective: Use SignalR for notification between Web API, and TypeScript/JavaScript based Web App, where Web API and the Web App is hosted in different domain. Enabling SignalR and CORS on Web API: Create a standard Web API project, and install the following NuGet packages: Microsoft.
WebSockets is actually the underlying transport that SignalR uses, at least most of the time. SignalR has the ability to fall back to other ways of transporting messages, such as long-polling over HTTP. This is useful in situations where you don't have WebSockets support.
Azure SignalR Service provides REST API to support server to client communication scenarios, such as broadcasting. You can choose any programming language that can make REST API call. You can post messages to all connected clients, a specific client by name, or a group of clients.
I use a class like this:
public class OAuthTokenProvider : OAuthBearerAuthenticationProvider { private List<Func<IOwinRequest, string>> _locations; private readonly Regex _bearerRegex = new Regex("((B|b)earer\\s)"); private const string AuthHeader = "Authorization"; /// <summary> /// By Default the Token will be searched for on the "Authorization" header. /// <para> pass additional getters that might return a token string</para> /// </summary> /// <param name="locations"></param> public OAuthTokenProvider(params Func<IOwinRequest, string>[] locations) { _locations = locations.ToList(); //Header is used by default _locations.Add(x => x.Headers.Get(AuthHeader)); } public override Task RequestToken(OAuthRequestTokenContext context) { var getter = _locations.FirstOrDefault(x => !String.IsNullOrWhiteSpace(x(context.Request))); if (getter != null) { var tokenStr = getter(context.Request); context.Token = _bearerRegex.Replace(tokenStr, "").Trim(); } return Task.FromResult<object>(null); } }
Which instead of just passing on the token to the header, parses it and sets it on the context.
Then it could be used in your app configuration like this:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions { Provider = new OAuthTokenProvider( req => req.Query.Get("bearer_token"), req => req.Query.Get("access_token"), req => req.Query.Get("token"), req => req.Headers.Get("X-Token")) });
Then the following styles of requests would have their token un-encrypted, for use with authentication and authorization:
GET https://www.myapp.com/authorized/endpoint?bearer_token=123ABC HTTP/1.1 GET https://www.myapp.com/authorized/endpoint?access_token=123ABC HTTP/1.1 GET https://www.myapp.com/authorized/endpoint?token=123ABC HTTP/1.1 GET https://www.myapp.com/authorized/endpoint HTTP/1.1 X-Token: 123ABC GET https://www.myapp.com/authorized/endpoint HTTP/1.1 Authorization: 123ABC
This how I solved it
var authData = localStorageService.get('authorizationData'); var token = authData.token; $.signalR.ajaxDefaults.headers = { Authorization: "Bearer " + token };
No change on the server side code
Hope it helps someone
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With