Tuesday, June 03, 2014

Using JSON Web Tokens authentication in Angular Web API request


Introduction


There are basically two different ways of implementing server side authentication for apps with a frontend and an API:
  • The most adopted one, is Cookie-Based Authentication (you can find an example here) that uses server side cookies to authenticate the user on every request.
  • A newer approach, Token-Based Authentication, relies on a signed token that is sent to the server on each request.
In this post we will implement API authentication based on standard JSON Web Token (JWT).


ASP.Net Web API


There is an open project JwtAuthForWebAPI implement a DelegatingHandler that creates a new ClaimsPrincipal based on the incoming token and assigns it to the current thread.

1. You can install the NuGet package for this library at https://www.nuget.org/packages/JwtAuthForWebAPI/.

2. Register the handler in your WebApiConfig.Register() method:


var tokenBuilder = new SecurityTokenBuilder();
var configReader = new ConfigurationReader();

var jwtHandlerSharedKey = new JwtAuthenticationMessageHandler
{
    AllowedAudience = configReader.AllowedAudience,
    Issuer = configReader.Issuer,
    SigningToken = tokenBuilder.CreateFromKey(configReader.SymmetricKey),
    PrincipalTransformer = new SimplePrincipalTransformer()
};

config.MessageHandlers.Add(jwtHandlerSharedKey);

3. Secure your controllers and/or their actions with the [Authorize] attribute - per standard ASP.NET authorization practices.

[Authorize]
public string Get(string id)
{
...
}

4. Assign a token when user login with correct password.

var configReader = new ConfigurationReader();

var key = Convert.FromBase64String(configReader.SymmetricKey);
var credentials = new SigningCredentials(
    new InMemorySymmetricSecurityKey(key),
    "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
    "http://www.w3.org/2001/04/xmlenc#sha256");

var tokenDescriptor = new SecurityTokenDescriptor
{
    Subject = new ClaimsIdentity(new[]
    {
        new Claim(ClaimTypes.Name, "bsmith"), 
        new Claim(ClaimTypes.GivenName, "Bob"),
        new Claim(ClaimTypes.Surname, "Smith"),
        new Claim(ClaimTypes.Role, "Customer Service")
    }),
    TokenIssuerName = "corp",
    AppliesToAddress = configReader.AllowedAudience,
    SigningCredentials = credentials
};

var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);

return tokenString;

Angular Client Side



1. The first step on the client side using AngularJS is to retrieve the JWT Token and have the JWT saved on sessionStorage.

myApp.controller('UserCtrl', function ($scope, $http, $window) {
  $scope.user = {username: 'john.doe', password: 'foobar'};
  $scope.message = '';
  $scope.submit = function () {
    $http
      .post('/authenticate', $scope.user)
      .success(function (data, status, headers, config) {
        $window.sessionStorage.token = data.token;
        $scope.message = 'Welcome';
      })
      .error(function (data, status, headers, config) {
        // Erase the token if the user fails to log in
        delete $window.sessionStorage.token;

        // Handle login errors here
        $scope.message = 'Error: Invalid user or password';
      });
  };
});


2. Add Authorization header for every outgoing request:


myApp.factory('authInterceptor', function ($rootScope, $q, $window) {
  return {
    request: function (config) {
      config.headers = config.headers || {};
      if ($window.sessionStorage.token) {
        config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
      }
      return config;
    },
    response: function (response) {
      if (response.status === 401) {
        // handle the case where the user is not authenticated
      }
      return response || $q.when(response);
    }
  };
});

myApp.config(function ($httpProvider) {
  $httpProvider.interceptors.push('authInterceptor');
});

Reference:
1.  Cookies vs Tokens. Getting auth right with Angular.JS
2. Techniques for authentication in AngularJS applications
3. JwtAuthForWebAPI

Friday, May 16, 2014

AngularJS

1. AngularJS
AngularJS is an open-source web application framework, maintained by Google and community, that assists with creating single-page applications, one-page web applications that only require HTML, CSS, and JavaScript on the client side.

A very good introduction video by Dan Wahlin:
AngularJS Fundamentals in 60 Minutes - Modules, Routes and Factories

The AngularJS Magazine

Miško Hevery discusses the advantages and disadvantages of various design choices when structuring an app in AngularJS, and some of the best practices in the development.
AngularJS MTV Meetup: Best Practices (2012/12/11) 

2. Yeoman
Miško Hevery suggest Yeoman generator for AngularJS. It will make Angular development much easy with Yeoman & generator-angular.

Several open source tools need:
a. Install Node.js
b. Install Ruby, also make sure that path to Ruby bin folder is added to %PATH%
c. Install Git
d. Install compass, bower, and generator-angular

npm install -g bower
npm install -g bower
npm install -g generator-angular
 
restarted cmd window and ran "bower install" in the app folder After that


e. Once we have Node, we’ll install generator-angular which will also automatically install Yeoman, Grunt, and Bower.
 
Now create a project folder, and change current folder to project folder
mkdir myApp cd myApp
bower install
npm install generator-angular    # Local install to myApp
yo angular:app myApp 
 
More generators
 
f. Grunt work


grunt server

3. Bootstrap
Code a Responsive Website with Bootstrap 3 - [Lecture 1]

Thursday, March 20, 2014

Bridge Mode Workaround for Rogers Router CGN2-ROG

  1. Log into your CGN2-ROG, normally located at 192.168.0.1
  2. Credentials are cusadmin/password by default, because it’s a magical star child who wants to be different.
  3. If you can’t log in, factory reset it, or use the usb unlocker they may or may not have been included with the device.
  4. Go to 192.168.0.1/user/setup-capability.asp
  5. Disable everything, hit apply. This will place the router into bridge mode. You will NOT be able to access the router now. If you need to, I’d recommend factory reset. It’s possible to directly connect a machine to the router, and access the router through it’s external IP, but just…don’t do that.
  6. Set up your second router, plug the ethernet cable into the LAN port 1 of the CGN2-ROG, and into the WAN port of the new router. Turn it on.
  7. You should be good to go, and can treat your new router as the main router. For all intents and purposes, the CGN2-ROG is now just a fancy internet box.

Monday, February 10, 2014

Custom JQuery Validation Method and Message

Validate forms like you've never validated before! See full documentation here.

List of built-in Validation methods


A set of standard validation methods is provided:

    required – Makes the element required.
    remote – Requests a resource to check the element for validity.
    minlength – Makes the element require a given minimum length.
    maxlength – Makes the element require a given maxmimum length.
    rangelength – Makes the element require a given value range.
    min – Makes the element require a given minimum.
    max – Makes the element require a given maximum.
    range – Makes the element require a given value range.
    email – Makes the element require a valid email
    url – Makes the element require a valid url
    date – Makes the element require a date.
    dateISO – Makes the element require an ISO date.
    number – Makes the element require a decimal number.
    digits – Makes the element require digits only.
    creditcard – Makes the element require a credit card number.
    equalTo – Requires the element to be the same as another one

For example:

<input id="yourEmail" name="yourEmail" class="required email" />
<input id="confirmEmail" name="confirmEmail" equalTo="#yourEmail" />

Now let's implement our custom validation method "naPostal" to validate Canada/US postal code:

<script type="text/javascript">

        jQuery.validator.addMethod("naPostal", function (postal, element) {
            if (this.optional(element)) return true;
            var ctyField = $(element).attr("countryField");
            if (ctyField && $(ctyField).val() == "CA") return postal.match(/[a-zA-Z][0-9][a-zA-Z](-| |)[0-9][a-zA-Z][0-9]/);
            if (ctyField && $(ctyField).val() == "US") return postal.match(/^\d{5}(?:[\s-]\d{4})?$/);
            return postal.match(/^\d{5}-\d{4}$|^\d{5}$|^[a-zA-Z][0-9][a-zA-Z](| )?[0-9][a-zA-Z][0-9]$/gm);
        }, "Invalid postalcode");

        jQuery.extend(jQuery.validator.messages, {
            //Custom error message
            required: "Required field",
            email: "Please enter a valid email address."
        });

</script>

So we can use this method in our HTML code:

<input id="postalCode" name="postalCode" class="required naPostal" countryField="#countryCode" />
<select id="countryCode" name="countryCode">
    <option value="CA">Canada</option>
    <option value="US">USA</option>
</select>