4

Following a couple tutorials on adding authentication using jsonwebtoken, passport, and passport-local I've become stuck on integrating it into my project. I want it so that any requests to any of the API endpoints require authentication, and also any requests to the front end which touch the API require authentication.

What is happening now is I can get a user to log in and register but once they are logged in they are still unable to visit a page which is requiring authentication. The user gets a 401 error. It's like the token isn't being passed correctly in the request.

I tried adding an 'auth interceptor' too

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');
});

But this didn't seem to do the trick either.
What am I forgetting or missing?

EDIT:

After entering creds and clicking log in I get this error in chrome console

GET http://localhost:3030/members/ 401 (Unauthorized)

But my nav links show up as they're supposed to after I've successfully authenticated.
I also get this error in my terminal where I'm running Node

UnauthorizedError: No authorization token was found
    at middlware (/ncps-mms/node_modules/express-jwt/lib/index.js)
    ...

EDIT:

It has a lot to do with this line of my server routes when I inject my auth object. Basically I think my auth token isn't getting sent with my GET request. But I thought that this is what happens when I pass my auth object into the GET request.

EDIT:

Added image of GET request.
Screenshot of GET request in Chrome.

EDIT/UPDATE:

I believe I've made my way past my authentication problem but the issue of my members-view state continues to fail to render after authenticated. I've pushed my latest changes to github and if you pull the latest and run you will see that you can authenticate but clicking the View link fails to load the view.

gh0st
  • 1,653
  • 3
  • 27
  • 59
  • Did you debug to check if you go in the if than is around the header ? – Walfrat Apr 12 '16 at 07:27
  • @Walfrat I don't understand what you're asking. – gh0st Apr 12 '16 at 23:20
  • Did you use the debogger of your browser and put a breakpoint to see if the configer.header.Authorization line was executed ? – Walfrat Apr 13 '16 at 08:38
  • I've made some progress but my view still does not render even after passing authentication. Please see my update to the OP. – gh0st Apr 13 '16 at 18:26
  • 2 things : in your login you use both .error and .thne function. Usually you either use .succes/.error or .then(successCallback, errorCallback). I don't know if it may cause some trouble. Second you should do an angular.run that will add listener for all ui-router events so you'll be able to track error with your states. – Walfrat Apr 14 '16 at 07:30

2 Answers2

1

Sorry, didn't actually have time to debug the problem but I suspect your issue could be with the header of your HTTP request.

Looking at the trace produced by my chrome browser, your client currently do not supply the "Authorization" key value pair to the HTTP request header?

Something like;

Key: Authorization Value: Bearer [TOKEN_VALUE]

Tried debugging using the Postman rest application by providing the http request with the Authorization key/value pair specified in the header and the server could tell me that the token value I was trying to give is a malform Json web token.

Whereas If I take away the Authorization key/value pair (which is what your client is using to communicate, I could reproduce the same error.

U might want to try modifying your client to include the authorization key and see if it works. Let me know if it doesn't, we can then look at other solution.

Check out my postman screenshots. Token malform Token not found

Samuel Toh
  • 18,006
  • 3
  • 24
  • 39
  • So that is definitely the problem. Using postman, if I provide the authorization header and the 'Bearer [token]' I'm able to hit my API. But how do I enter that into my logic? Isn't that handled here? https://github.com/gh0st/ncps-mms/blob/master/client/src/routes.js#L11-L20 – gh0st Apr 12 '16 at 17:21
  • Good to know the issue. Was trying to debug your client this morning by putting a few simple $log.debug statements in there but it doesn't seems to work, which it would have for normal angular app? Maybe the reason is me not understanding how Gulp works. Have never use it before. Sounds like you do have a line of code that append the Authorization key to the HTTP Header here=> https://github.com/gh0st/ncps-mms/blob/master/client/src/controllers/controllers.js#L57-L57 – Samuel Toh Apr 13 '16 at 01:10
  • And it sounds like it is not getting utilized by the client when it is doing HTTP calls to hit API when auth is required. Can you please try adding that 1 line (see above) to places where $http is being used to GET/POST resources that requires authentication? I'm trying to do it myself but somehow the client doesn't seem to pick up my changes. As mentioned before, it could be just my lack of gulp knowledge. Let me know if that works. – Samuel Toh Apr 13 '16 at 01:14
  • I've made some progress but my view still does not render even after passing authentication. Please see my update to the OP. You can run the app by running `npm run watch` to transpire and then actually start the app with `npm start`. The `npm run watch` will compile your latest changes to anything on the server side. – gh0st Apr 13 '16 at 18:26
  • Tried doing npm run watch but got hit by an error. I think its my limited knowledge with the babel stuff that you are using. I have raised a github issue on your project. Will appreciate if you can help me to get setup. Also if you think you might have found the core issue for your question, will greatly appreciate if you can mark it as answered too! Thanks – Samuel Toh Apr 14 '16 at 11:46
  • Don't forget you need to have mongo, and it needs to be running. – gh0st Apr 14 '16 at 15:19
  • Nope if you look at the error messages provided by me on the issue of your github project clearly it is not about whether mongodb is running or not. It is something along hey I don't recognise the import key word so My initial thought was probably it is due to my node version but using nvm to pump up to 1 of the latest version still doesn't work. – Samuel Toh Apr 14 '16 at 18:03
  • You don't have gulp installed? – gh0st Apr 15 '16 at 15:16
  • As mentioned in the GitHub issue. I followed the setup instruction in the readme.md – Samuel Toh Apr 16 '16 at 13:59
1

https://github.com/gh0st/ncps-mms works fine for me after a few fixes for resolve...

See https://github.com/gh0st/ncps-mms/pull/2

client/src/routes.js

/* jshint esversion: 6 */
/* jshint node: true */
import angular from 'angular';
import 'angular-ui-router';

angular.module('ncps.routes', ['ui.router'])
.config(($stateProvider, $urlRouterProvider) => {
    $urlRouterProvider.otherwise('/members/login');

    $stateProvider
    .state('login', {
        url: '/members/login',
        templateUrl: 'members/members-login.html',
        controller: 'AuthController',
        onEnter: ['$state', 'auth', function($state, auth) {
            if (auth.isLoggedIn()) {
                console.log('Going to /members/...');
                $state.go('members', {
                    // 'headers': {
                    //     'Authorization': 'Bearer ' + auth.getToken()
                    // }
                });
            }
        }]
    })
    .state('register', {
        url: '/members/register',
        templateUrl: 'members/members-register.html',
        controller: 'AuthController',
        onEnter: ['$state', 'auth', function($state, auth) {
            if (auth.isLoggedIn()) {
                $state.go('members');
            }
        }]
    })
    .state('members', {
        url: '/members',
        templateUrl: 'members/members-view.html',
        resolve: {
            members: function($http, auth) {
                console.log('Trying to get /members....');
                return $http.get('/members', {
                    headers: {
                        'Authorization': 'Bearer ' + auth.getToken()
                    }
                }).then(function(response){
                    return response.data;
                });
            }
        },
        controller: 'MembersController as membersCtrl'
    })
    .state('new', {
        url: '/members/add',
        templateUrl: '/members/members-add.html',
        controller: 'MembersSaveController as newMemberCtrl'
    })
    .state('test', {
        url: '/members/test',
        template: 'This is a test.'
    });
});

client/src/controllers/controllers.js

/* jshint esversion: 6 */
/* jshint node: true */
import angular from 'angular';
angular.module('ncps.controllers', [])

.controller('MembersController', ['$http', 'auth', 'members', function($http, auth, members) {
    console.log('Members retrieved');
    this.members = members;
}])

.controller('MembersSaveController', function($stateParams, $state, $http) {
    this.member = $state.member;

    this.saveMember = function(member) {
        $http.post('/members', member).then((res, member) => {
            $state.go('members');
        });
    };
})

.controller('NavController', ['$scope', 'auth', function($scope, auth) {
    $scope.isLoggedIn = auth.isLoggedIn;
    $scope.currentUser = auth.currentUser;
    $scope.logOut = auth.logOut;
}])

.controller('AuthController', ['$scope', '$state', 'auth', function($scope, $state, auth) {
    $scope.user = {};

    $scope.register = function() {
        auth.register($scope.user).error(function(error) {
            $scope.error = error;
        }).then(function() {
            $state.go('members');
        });
    };

    $scope.logIn = function() {
        auth.logIn($scope.user).error(function(error) {
            $scope.error = error;
        }).then(function() {
            $state.go('members');
        });
    };

    $scope.logOut = function() {
        auth.logOut().error(function(error) {
            $scope.error = error;
        }).then(function() {
            $state.go('members');
        });
    };
}]);
malix
  • 3,566
  • 1
  • 31
  • 41
  • 1
    Would you be able to explain what was happening and why adding/modifying your code fixed it? – gh0st Apr 18 '16 at 18:24
  • 1
    resolve is trying to inject `members`, but for that to happen, it has to be declared as the last parameters on the MembersController controller... Also, auth was absent in there and silently failing in ```headers: { 'Authorization': 'Bearer ' + auth.getToken() }``` +1 ? :) – malix Apr 18 '16 at 18:35