0

[Q1] What advantage does an HTTP Interceptor provide on modifying the config.headers["Authorization"] (frontend AngularJS) to contain the value of token when I can verify the requests by checking the req.cookies object? (at the backend NodeJS)

I am trying to understand how JSON web tokens function. The demo application I have setup has a login functionality.

  1. On GET '/login' I am able to produce a token, set a cookie with it.
  2. On the frontend, I can access a JSON object containing the token.
  3. I can view the cookie in the developer console.

Nodejs:

index.js - login route

router.post('/login', function(req, res, next) {
  Authenticator.find(req.cookies.token, req.body, Heartbeat.common, function(err, warning, data){
    if(err) {
      res.status(404).send({token:false, warning: null, error:err});
    } else if(warning){
      res.status(200).send({token:true, warning: warning, error:null});
    } else {
      res.cookie('token', data, {maxAge: 3600000, httpOnly:true});
      res.status(200).json({token:true, error: null});
    }
  });
});

Authenticator.ctrl.js - Authenticator.find()

find: function(token, user, heartbeat, callback) {
  if(!token) {
    Auth.findOne({email:user.email}, function(err, data){
      if(err) {
        console.log(err);
      } else {
        if(data) {
          if(data.checkHash(user.password)) {
            callback(null, null,TokenMaker.createToken(user.email, heartbeat));
          } else {
            callback(Errors.login.strict.MISMATCH, null, null);
          }
        } else {
          callback(Errors.login.strict.NOT_REGISTERED, null, null);
        }
      }
    });
  } else {
    callback(null, Errors.login.warning.ACTIVE_REFRESH, null);
  }
},

Angular Controller

app.controller('userAccessCtrl', ['$scope', '$http', function ($scope, $http){
  $scope.user = {
    email: "someone@some.com",
    password: "12345679"
  };
  $scope.error = {};
  $scope.loginAccess = function(user) {
    var submitReady = true;
    var emailStatus = EmailValidator.email(user.email);
    var passwordStatus = EmailValidator.password(user.password);
    if(typeof emailStatus === "string") {
      $scope.error.email = emailStatus;
      submitReady = false;
    }
    if(typeof passwordStatus === "string") {
      $scope.error.password = passwordStatus;
      submitReady = false;
    }
    if(submitReady) {
      $scope.error = {}
      var data = $scope.user;
      $scope.user = {};
      $http.post('/login', data)
        .then(function(success){
            console.log(success);
          },function(error){
            console.log(error);
        });
    }

}
}]);

Console response:

{
  "data": {
    "token":true,
    "error":null
  },
  "status":200,
  "config":{
    "method":"POST",
    "transformRequest":[null],
    "transformResponse":[null],
    "url":"/login",
    "data":{
      "email":"someone@some.com",
      "password":"12345679"
    },
    "headers":{
      "Accept":"application/json, text/plain, */*",
      "Content-Type":"application/json;charset=utf-8"
    }
  },
  "statusText":"OK"
}
Amresh Venugopal
  • 9,299
  • 5
  • 38
  • 52
  • How about some code of the interceptor? Also you usually find people using local and session storage instead of cookies. Ideally you would store the token after successful auth call to your backend, and interceptor simply takes the value from it and builds header for every request. Using cookies vs storage depends how your token is set up, does it include expiration date for example, and many other factors. Read the difference. – Vaelyr Apr 17 '16 at 08:05
  • @Vaelyr I referred to this SO question [link](http://stackoverflow.com/questions/3220660/local-storage-vs-cookies). I am setting expiry times for the cookies as well as the token. I am curious about the use of an interceptor, when every consecutive request will anyway contain the token in the cookie (if storing the JWT does not pose any burden on the server) – Amresh Venugopal Apr 17 '16 at 08:26
  • As I understand form your second question, is that you are not able to get the cookie working? No matter what solution you choose, you have to pass it to the back-end to validate, either through header or cookie. It is stateless mechanism so there it is opposite of burdening server - there is no session. Can you show the code where you create the header? – Vaelyr Apr 17 '16 at 10:36
  • @Vaelyr I have added the code. The developer console shows the created token but I can't see it in the success object – Amresh Venugopal Apr 17 '16 at 14:01
  • So I still don't see any angular interceptors. You need to have an interceptor which puts the initial authentication token (which you store as cookie I assume), back into the response, using `$cookies` for example. – Vaelyr Apr 17 '16 at 14:50

1 Answers1

1

Actually it's a wrong to use cookies and JWT tokens. JWT token is much better for authentication than cookies. When you use token, your server doesn't need to store session in database of memory and this is a big advantage for your application - you can scale you application, add new servers without thinking about how to sync sessions between servers.

In short words, when you use JWT token your flow is next:

  • frontend (in you case it's an angular) sends login and password to /login route
  • backend checks credentials and sends back token (in request body, not in cookies)
  • frontend app saves token in local storage or session storage of browser
  • and you can write HTTP Interceptor which will intercepts all requests to backend and it will attach "Authorization" header to all requests, it looks like next:

    Authorization: Bearer here-is-your-jwt-token

  • backend can check this authorization header and if it is correct (look at http://jwt.io to read how verification works) backend can serve you request.

sergiy.dragunov
  • 780
  • 6
  • 9
  • "Actually it's wrong to use cookies and JWT tokens. JWT token is much better for authentication than cookies" can you elaborate on why? I have read about XSS and CSRF attacks and they say storing token in cookies is safer by keeping httpOnly true so that cookies can't be accessed by js. – Amresh Venugopal Apr 18 '16 at 08:55
  • 1
    Token very often uses with API, when some server provide API for mobile, desktop or website applications. The main advantage of tokens is a stateless - it means you server doesn't need to store (in memory, Redis, databases, files...) tokens, server just generate JWT token and return it back to application. This allows you simple scale your application , If your application is very loaded, your users make many requests to your backend, validating user's session for all requests will take longer time than validating JWT token. – sergiy.dragunov Apr 19 '16 at 11:43
  • 1
    Of course session cookie with flag HTTPonly is more secure and much simple to implement, but if your backend needs to serve requests from different hosts (if you are going to create mobile or desktop application) it will be better to use JWT tokens and not to use session anymore. – sergiy.dragunov Apr 19 '16 at 11:52
  • All I have done is 1. create a token 2. `res.cookie('token', data, {maxAge: age});` The token is accessible to my angular app. I haven't set any sessions by myself, also, could you direct me to a resource which explains the use of storing tokens when they can be set in headers? – Amresh Venugopal Apr 20 '16 at 12:11
  • Maybe this tutorial helps you http://angular-tips.com/blog/2014/05/json-web-tokens-examples/ – sergiy.dragunov Apr 22 '16 at 15:42
  • this is a grate article about using JWT tokens https://stormpath.com/blog/jwt-authentication-angularjs – sergiy.dragunov May 09 '16 at 09:48