Web API / OWIN, SignalR & Authorization

Peter Trenery picture Peter Trenery · Apr 10, 2014 · Viewed 14.3k times · Source

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.

Answer

calebboyd picture calebboyd · May 7, 2014

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