OAuth2 in thinktecture IdentityServer v2: Implicit Grant Flow with JavaScript

Our thinktecture IdentityServer version 2 will be a very different and very powerful identity beast!

Dominick already talked quite a bit about the features and how to use them. And Brock is surely at it as well.

Today I will show how to use IdentityServerv2 to implement the OAuth2.0 implicit grant flow as outlined in the official OAuth2 spec – and we are going to use a JavaScript client for that.

For the sake of a little bit of mobile-ness I am going to use KendoUI Mobile to have a native looking mobile UI (which you could then combine e.g. with Cordova/PhoneGap to create a native app).

We are going to look to secure a super novel and world overtaking… TODO app Smile

1


Admittedly, this is only the basic gist of what an app should look like and feature-wise we will focus on the OAuth part today.
First let’s head to IdentityServer an create a new OAuth Client like this:

idsrv1


One important part of the configuration is the callback/redirect URI. This is where the IdP sends us the token to.

In addition, we need a relying party/resource we can use to create tokens for and which will accept these tokens coming from our JavaScript clients.

idsrv2


Alright, time to jump on to the client side.
I try to encapsulate my JS code as much as possible. One nice pattern to get a basic structure is MVVM and KendoUI has good support for that.

The page above for the Start tab has a viewmodel which does just fire up the OAuth process (in this case the authentication):

   1:  var startViewModel = kendo.observable({
   2:      openLoginView: function () {
   3:          oauth2ViewModel.openAuthWindow(
   4:             endpoints.IdpOauthEndpointUrl);
   5:      }
   6:  });


The OAuth viewmodel holds the token and offer methods to kick off the login process and parse the token from the return URL.

   1:  var oauth2ViewModel = kendo.observable({
   2:      token: "",
   3:      
   4:      openAuthWindow: function () {
   5:          var url = endpoints.IdpOauthEndpointUrl + "?" 
   6:             + $.param(oAuthConfig);
   7:          window.open(url, "Login", "height=500,width=350");
   8:      },
   9:      
  10:      loginCallback: function (params) {
  11:          this.token = params["access_token"];
  12:          window.kendoMobileApplication.navigate("#todosPage");
  13:      }
  14:  });


In order to craft the correct URL for IdentityServer we need a couple of parameters which need to correspond to what we previously set up in IdSrv for the OAuth client and the RP (see the IdSrv screenshots above):

   1:  var endpoints = {
   2:      IdpOauthEndpointUrl: "https://localhost/idsrv/issue/
   3:         oauth2/authorize"
   4:  };
   5:   
   6:  var oAuthConfig = {
   7:      client_id: "tt_tudus",
   8:      scope: "http://tt.com/mobile/todos",
   9:      response_type: "token",
  10:      redirect_uri: "http://localhost/simpletudus/
  11:         oauthcallback.html"
  12:  }


Alright. Let’s look at the flow now.
Once we clicked on Login a new window pops up which loads the IdentityServer login page:

2


After loging into IdSrv we get the resource consent page and choose to allow access:

3


IdSrv will now send the token to callback URL specified earlier in the IdSrv config.

This URL looks something like this:

http://localhost/simpletudus/oauthcallback.html#access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI…
&token_type=urn:ietf:params:oauth:token-type:jwt&expires_in=35999


The code of the oauthcallback.html page is pretty simple. It parses the token from the hash (#) part of the URL and fires an event on the calling page to pass over the token (see the Google OAuth developers page for more details on the process):

   1:  <script src="js/libs/jquery-1.7.1.min.js" type="text/javascript"></script>
   2:  <script src="js/libs/jquery.ba-bbq.min.js" type="text/javascript"></script>
   3:   
   4:  <script type="text/javascript">
   5:      //var params = {}, queryString = location.hash.substring(1),
   6:      //    regex = /([^&=]+)=([^&]*)/g, m;
   7:   
   8:      //while (m = regex.exec(queryString)) {
   9:      //    params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  10:      //}
  11:      
  12:      var params = $.deparam.fragment(
  13:         location.hash.substring(1));
  14:      
  15:      window.opener.oAuthCallback(params);
  16:      window.close();    
  17:  </script>


Note
: I am using jQuery BBQ in the above code to parse the URL, the commented code shows how to do it without any external library.

In the main page we have some kind of a proxy event handler which just passes the token on to the above shown OAuth viewmodel:

   1:  <script>
   2:      function oAuthCallback(params) {
   3:          oauth2ViewModel.loginCallback(params);
   4:      }
   5:  </script>


In the OAuth viewmodel login callback method we then simply set the token and trigger navigation to the TODO items page.

When hitting the refresh button in the upper left side of the Items view the actual call to the resource is made with standard jQuery. This happens in the loadTodos call:

   1:  var todosViewModel = kendo.observable({
   2:      todosSource: new kendo.data.DataSource(
   3:         { sort: { field: "title", dir: "asc" } }),
   4:      
   5:      loadTodos: function () {
   6:          var self = this;
   7:   
   8:          dataservices.getTodos(oauth2ViewModel.token)
   9:              .done(function (data) {
  10:                  self.todosSource.data(data);
  11:              });
  12:      }
  13:  });


The data services logic is embedded in its own ‘class’ and simply uses the token acquired before to set the appropriate Bearer Authorization header before making the jQuery GET request against the TODO items resource (which is implemented with ASP.NET Web API, BTW):…

   1:  var dataservices = (function () {
   2:      function beforeSend(xhr, token) {
   3:          xhr.setRequestHeader("Authorization", 
   4:             createBearerHeader(token));
   5:      }
   6:   
   7:      function createBearerHeader(token) {
   8:          var header = "Bearer " + token;
   9:          return header;
  10:      }
  11:   
  12:      return {
  13:          getTodos: function (token) {
  14:              return $.ajax({
  15:                  url: endpoints.ServiceEndpointUrl,
  16:                  type: "get",
  17:                  dataType: "json",
  18:                  beforeSend: function (xhr) { beforeSend(xhr, token); }
  19:              });
  20:          }
  21:      };
  22:  }());


And voila…:

4


So please head to GitHub and get the IdSrv bits and give us feedback – thanks!


The entire code for this complete end-to-end sample can be found on GitHub.

Hope this helps.