I'm using the code from this blog to make an authentication module for my angular app.
I have a test page that includes a login form, a submit button and a "profile" button that will query a restricted route.
<div class="container-fluid" ng-controller="AuthCtrl as auth">
<input type="text" ng-model="auth.user.username">
<input type="text" ng-model="auth.user.password">
<button ng-click="auth.login(auth.user)">LOGIN</button>
<button ng-click="auth.profile()">PROFILE</button>
</div>
The restricted route I'm querying after login is defined as:
const authenticate = expressJwt({
secret: SECRET
});
app.get('/me', authenticate, function(req, res) {
res.status(200).json(req.user);
});
The login works fine. I receive a token that I put in sessionStorage. When I click on the profile button (request to /me) I get an unauthorized error.
If I refresh the page and click again on profile I do get the excpected behaviour. (/me returns user data with no error)
If I delete the token manually after that, I still have access to /me until I refresh the page.
This is my service:
function loginService($http) {
this.login = function(user) {
return $http.post('/auth', user).then(
function(response) {
return response.data;
},
function(response) {
return response;
});
};
this.profile = function() {
return $http.get('/me').then(
function(response) {
return response.data;
},
function(response) {
return response;
});
};
}
angular
.module('app')
.service('loginService', loginService);
And this is my controller with the httpProvider:
function AuthCtrl($window, $http, loginService) {
this.user = {username: "", password: ""};
this.login = function(user) {
loginService.login(user).then(function(data) {
$window.sessionStorage.token = data.token;
});
};
this.profile = function() {
loginService.profile().then(function(data) {
console.log(data);
});
};
}
function config($httpProvider, $windowProvider) {
var window = $windowProvider.$get();
if(window.sessionStorage.token) {
var token = window.sessionStorage.token;
$httpProvider.defaults.headers.common.Authorization = 'Bearer ' + token;
}
};
angular
.module('app')
.config(config)
.controller('AuthCtrl', AuthCtrl);
Could the problem come from storing the token in sessionStorage or from the http provider?
Eventually I will implement the secure cookie method but I'd like to get this one solved before proceding further.
I finally figured out it was coming for the $httpProvider
code.
function config($httpProvider, $windowProvider) {
var window = $windowProvider.$get();
if(window.sessionStorage.token) {
var token = window.sessionStorage.token;
$httpProvider.defaults.headers.common.Authorization = 'Bearer ' + token;
}
};
The provider options wer set only once during app load.
Reloading the page would rerun the config code and enter the if(window.sessionStorage.token)
condition as expected.
To make this config dynamic, I had to create an interceptor (factory) like so:
function config($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
};
function authInterceptor($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
return config;
},
responseError: function (rejection) {
if (rejection.status === 401) {
console.log("not authorised");
}
return $q.reject(rejection);
}
};
};
angular
.module('app')
.config(config)
.controller('AuthCtrl', AuthCtrl)
.factory('authInterceptor', authInterceptor);