Pages

Wednesday, 1 January 2014

Securing WebApi with Live Id authentication token

I wanted to create a small Windows Store App which would save data using a custom WebApi. I didn’t want to ask the user to register and create a new account, so I opted to use Windows Live with wl.signin as the scope to implement a single sign-on solution.

I will be using the User Identifier as a unique identifier for user specific data to show only the relevant data to the user. I do not want to store any personal details as the app will allow users to add, edit and delete only their own data and profile data will not be required to do this.

I wanted to implement the WebApi as a MVC5 WebApi2 solution which would allow me to create a web client that consumes the same WebApi at a later stage. This approach would also allow me to learn about the implementation of OWIN authentication middleware.

Getting to the bottom of how I would authorise access to the WebApi resources using the OWIN pipeline took me much longer than I anticipated and decided to create this blog post to help others that want to do the same.

I don’t know if this is the best way or even the correct way of implementing this and I will be researching this a lot more to be sure it is secure and implemented correctly. Please feel free to comment on this approach and let me know if it should be changed or can be improved.

Please note I have simplified the example code significantly for brevity and have no error handling, please use the code as an example only.

If you want to follow this tutorial please create a solution as follow:

1.) Create a new Windows Store App using this Blank App (XAML) template

image

2.) It is very important to associate the app with your store account. This will update the app manifest to allow us to use the Live Connect APIs LiveAuthClient to sign users in.

image

3.) Add the WebApi project to the solution

image

image

4.) Change the authentication to ‘No Authentication’

image

Signing the user in with Live SDK in the Windows Store App

The first thing we want to do is to get an authentication token that will be used to authorise requests to the WebApi. I opted to use the Nuget package to reference the Live Connect APIs instead of installing the SDK.

Add the LiveSDK package using the Package Manage Console:

PM> Install-Package LiveSDK
Installing 'LiveSDK 5.5'.
Successfully installed 'LiveSDK 5.5'.
Adding 'LiveSDK 5.5' to SignMeIn.
Successfully added 'LiveSDK 5.5' to SignMeIn.

It is important that we specify a redirect domain for the app, configure your app and specify a redirect domain.


Create a method in the MainPage class file to authenticate the user

private async Task<string> AuthenticateAsync()
{
try
{
var auth = new LiveAuthClient(“<<The redirect domain for the app>>”);
var loginResult = await auth.LoginAsync(new[] { "wl.signin" });
// ToDo: add code here to handle Login failure
if (loginResult.Status == LiveConnectSessionStatus.Connected)
{
return loginResult.Session.AuthenticationToken;
}
}
catch (Exception)
{
// ToDo: add code here to handle Login failure
throw;
}
return string.Empty;
}

It is worth reading up and understanding the core concepts of the Live Connect APIs


Next we add a method to retrieve data from the WebApi, I am using the Microsoft.AspNet.WebApi.Client Nuget package for this.

PM> Install-Package Microsoft.AspNet.WebApi.Client

Create the GetData method in the MainPage class file, the authentication token we got from the AuthenticateAsync method is set as the bearer token in the the auhorization header. The bearer token will be used by the WebApi to authorize access to the requested resource. At this stage the WebApi does not enforce any authorization and all requests will be allowed.

private async Task<string> GetData(string authenticationToken)
{
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("<<The root URL for your web application>>");
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", authenticationToken);

var respone = await httpClient.GetAsync("/api/values");

var content = await respone.Content.ReadAsStringAsync();

return content;
}

Authorising the WebApi requests


We will be using OWIN Middleware to validate the bearer token passed in the authorization header and create a ClaimsIdentity with the claims issued by the Microsoft Live service to authorize requests to resources. The authentication token issued by Microsoft Live is a JsonWebToken which we need to unpack and validate the signature to ensure the token is tamper proof.


This can be done using OAuthBearerAuthenticationMiddleware by configuring it with the UseJwtBearerAuthentication extension method.


First of all we need to install the Microsoft.Owin.Host.SystemWeb and  Microsoft.Owin.Security.Jwt nuget packages.

Install-Package Microsoft.Owin.Security.Jwt

Install-Package Microsoft.Owin.Host.SystemWeb

Now we need to configure the OAuthBearerAuthenticationMiddleware by adding it to the OWIN pipeline. We do this by adding a Startup.cs class with an OwinStartupAttribute.

using Microsoft.Owin;

[assembly: OwinStartup(typeof(SignMeIn.Web.Startup))]

namespace SignMeIn.Web
{
using System.Security.Cryptography;
using Microsoft.Owin.Security.Jwt;
using Owin;

public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}

private void ConfigureAuth(IAppBuilder app)
{
// Create the signing key that will be used to validate the token
// This is based on the application secret
var sha256 = new SHA256Managed();
var secretBytes = System.Text.Encoding.UTF8.GetBytes("<< Your App Secret >>" + "JWTSig");
byte[] signingKey = sha256.ComputeHash(secretBytes);

app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AllowedAudiences = new[] { "<<the audience allowed>>" },
IssuerSecurityTokenProviders =
new[]
{
new SymmetricKeyIssuerSecurityTokenProvider(
"urn:windows:liveid", signingKey)
}
});
}
}
}

Now we can add the AuthorizeAttribute to our ApiControllers to limit access to requests that have a valid bearer token and retrieve the uid claim from the ClaimsIdentity.

public IEnumerable<string> Get()
{
var identity = this.User.Identity as ClaimsIdentity;
var uid = identity.Claims.First(c => c.Type == "uid");

return new string[] { "value1", "value2" };
}

If you have any issues with getting this to work, make sure you turn tracing on for OWIN by adding the following to the Web.Config. This will allow you to see any warings in the Dbug Output window

<system.diagnostics>
<switches>
<add name="Microsoft.Owin" value="Verbose" />
</switches>
</system.diagnostics>

Ensure that both applications start when you debug by setting the solution properties to multiple startup projects when you are testing this.


image

3 comments:

  1. Great post, thanks!
    But still can't get it to work. Can you please tell me what should I use as JWTSig in line 23? Where can I find it? Is it the decoded signature part of the JWT token?

    ReplyDelete
  2. http://stackoverflow.com/questions/28823991/login-from-universal-app-to-web-api-using-live-id

    ReplyDelete

  3. As for me as a great solution, developed and submitted clear. it will be interesting to try out.
    Richard Brown virtual dataroom

    ReplyDelete