AngularJS, $http and interceptor - every request received twice in nodejs - angularjs

I'm trying to use AngularJS' $http interceptor for adding a token on every API call.
This is my code (http://pastebin.com/x1EMGcVE):
.factory('authInterceptor', function(authorization, API) {
return {
request: function(config) {
var token = authorization.getToken();
if (config.url.indexOf(API) === 0 && token) {
config.headers.Authorization = token;
}
return config;
}
}
})
On my nodes backend I'm receiving the call with express:
app.route('/API-CALL')
.get(function(req, res) {
...
My problem is that every API request is received twice in nodejs, one request without the token added in Authorization and one with the token added.
Is this an issue with the interceptor? Outputting the config from the interceptor seems to show no issues and only the correct number of requests with the token added.
If I remove the:
$httpProvider.interceptors.push('authInterceptor');
calls are only made once, but of course without the token added.

Related

Add Firebase Token to Angular $HTTP header

So I want to add a firebase token to all http requests. I am using the angularJS 1.X framework.
I have an interceptor function which normally I would just add it like this:
.factory('Interceptor', function () {
interceptorFactory.request = function (config) {
config.token = firebaseToken;
return config;
};
return interceptorFactory;
})
.config(function ($httpProvider) {
$httpProvider.interceptors.push('Interceptor');
});
But the issue is the only way to get the firebase token is through a promise, so for that I would need to do something like this:
.factory('Interceptor', function () {
interceptorFactory.request = function (config) {
getFirebaseToken().then(function(token){
config.token = token;
return config;
});
};
return interceptorFactory;
})
.config(function ($httpProvider) {
$httpProvider.interceptors.push('Interceptor');
});
The problem though, is because the token is retrieved Asyncronously, the factory interceptor does not wait for promise to resolve, so the request is sent without the token. If anyone knows how to get around this that would be help full.
Also, I know I could just get the token before I make every http request but then that would cause a lot of duplicate code, and I can't get the token on application startup and just store it cause it has an expiration.

React.js run function on bootstraping

I can't find a way to fun a function once the app bootstraps it self. I am using bearer token authentication and if the user has logged in before the token is stored in local storage:
localStorage.setItem('access_token', response.body.access_token);
Then I am using interceptors to add a constant header to every request
authorizationInterceptor: {
enable: () => {
if(auth.loggedIn())
{
fetchIntercept.register({
request: function (url, config) {
config.headers.Authorization = 'Bearer ' + auth.getToken();
return [url, config];
}
});
}
}
}
The problem is I am running the authorizationInterceptor.enable() on login request, but if the user already has logged in and hits refresh I need to run the interceptor again. So is there a way to run a function once only after app bootstrapping is finished? I do not want to add a check in every fetch request, seems very redundant.

AngularJS interceptor not putting JWT Bearer in every request of node.js app

I put a JWT authentication system in a node app.
I used an interceptor to put the Bearer in every request. It works well if I call a restricted route within Angular or if I curl and specify the token in the header.
But if I enter the restricted route directly in my address bar, it doesn't work. There is no Bearer in the header, it doesn't go through the interceptor.
Here is my interceptor (client-side):
angular.module('myApp).factory('authInterceptor', function ($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.localStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.localStorage.token;
}
return config;
},
responseError: function (rejection) {
if (rejection.status === 401) {
// handle the case where the user is not authenticated
}
return $q.reject(rejection);
}
};
});
angular.module('myApp').config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
});
Here is my restricted route (server-side):
router.get('/restricted', expressJwt({secret: 'SecretStory'}), function(req, res) {
res.json({
name: 'You are allowed here !!'
});
})
How to make the bearer to be added to my request header on every request, even in typing the restricted route directly into the address bar?
When you enter a URL directly in the address bar you are circumventing your Angular code and, as you've discovered, the interceptor will not run.
You could try detecting when the URL in the address bar changes and try to work around the problem, but I would recommend against this.
Instead, I would approach this problem server-side by detecting a GET /restricted request with an Accept header of text/html (anything that is not application/json really). Then respond with HTML that includes your Angular code and request /restricted again using application/json when the page loads. This would be a good way to distinguish between explicit URL navigation and Angular requests and offers better hypermedia support to your API.

Satellizer causes Angular to pre-flight ALL of my rest queries with an OPTIONS request

If all servers responded to an OPTIONS request this would not be a problem, but Satellizer even causes Angular to pre-flight a GET request with Content-Type text/plain. In effect, it breaks half of my other REST queries.
After looking through the code and studying Angualr's httpProvider I realized that Sateliizer is intercepting every single request using httpProvider's interceptors array and adding the following:
var token = localStorage.getItem(tokenName);
if (token && config.httpInterceptor) {
token = config.authHeader === 'Authorization' ? 'Bearer ' + token : token;
httpConfig.headers[config.authHeader] = token;
}
So that every single request gets an Authorization header. Since I actually have only ONE request that needs an authorization header I modified the conditional statement:
if (token && config.httpInterceptor && httpConfig.auth===true) {
and then in my $http.get for the single service that actually needs authorization I add:
var config = {auth: true};
$http.get(googleUrl, config)
I use satellizer library for managing authorization. Since I also make REST calls to third party APIs, I don't want to include the Authorization header. Adding skipAuthorization:true in the configuration block solved my issue. For example:
(function () {
'use strict';
angular.module('weather')
.factory('weatherResource', ['$http', function ($http) {
return $http({
method: 'GET',
url: 'http://api.openweathermap.org/data/2.5/weather?q=Bangalore&appid=a50e83454ba54b9',
skipAuthorization: true
});
}]);
})();
Good luck.

implementing refresh-tokens with angular and express-jwt

I want to implement the Sliding expiration concept with json web tokens using angular, nodejs and express-jwt. I'm a little confused on how to do this, and am struggling to find any example of refresh tokens or and other material relating to sessions with these technologies/frameworks.
A few options I was thinking of were
Generating a new token with each request after the initial login
Keeping track of issued token on the server side along
But I'm honestly not sure, please help
I managed to implement this scenario.
What I've done...
On the server:
-Enable an API endpoint for signin. This endpoint will respond with the Json Web Token in the header. The client side has to catch it (with $http interceptors) and save it (I use local storage). The client will also manage the refreshed tokens sent by the server.
-On every request to the server configure a middleware in express to validate the token. At first I tried express-jwt module but jsonwebtoken was the right one for me.
For specific routes you may want to disable the middleware. In this case signin and signout.
var jwtCheck = auth.verifyJWT;
jwtCheck.unless = unless;
app.use('/api', jwtCheck.unless({path: [
'/api/auth/signin',
'/api/auth/signout'
]}));
-The middleware verifyJWT always responds with a token in the header. If the token needs to be refreshed a refreshed function is called.
jwtLib is my own library where the code lives to create, refresh and fetch jwt tokens.
function(req, res, next) {
var newToken,
token = jwtLib.fetch(req.headers);
if(token) {
jwt.verify(token, config.jwt.secret, {
secret: config.jwt.secret
}, function(err, decoded) {
if(err) {
return res.status(401).send({
message: 'User token is not valid'
});
}
//Refresh: If the token needs to be refreshed gets the new refreshed token
newToken = jwtLib.refreshToken(decoded);
if(newToken) {
// Set the JWT refreshed token in http header
res.set('Authorization', 'Bearer ' + newToken);
next();
} else {
res.set('Authorization', 'Bearer ' + token);
next();
}
});
} else {
return res.status(401).send({
message: 'User token is not present'
});
}
};
-The refresh function (jwtLib). As argument needs a decoded token, see above that jsonwebtoken resolve a decoded when call to jwt.verify().
If you create during signin a token with an expiration of 4 hours and have a refresh expiration of 1 h (1 * 60 * 60 = 3600 secs) that means that the token will be refreshed if the user has been inactive for 3 hours or more, but not for more than 4 hours, because the verify process would fail in this case (1 hour window of refreshing). This avoids generating a new token on each request, only if the token will expire in this time window.
module.exports.refreshToken = function(decoded) {
var token_exp,
now,
newToken;
token_exp = decoded.exp;
now = moment().unix().valueOf();
if((token_exp - now) < config.jwt.TOKEN_REFRESH_EXPIRATION) {
newToken = this.createToken(decoded.user);
if(newToken) {
return newToken;
}
} else {
return null;
}
};
On the client (Angularjs):
-Enable a client side for login. This calls the server endpoint. I use Http Basic Authentication encoded with base64.
You can use base64 angular module to encode the email:password
Note that on success I do not store the token on the localStorage or Cookie. This will be managed by the http Interceptor.
//Base64 encode Basic Authorization (email:password)
$http.defaults.headers.common.Authorization = 'Basic ' + base64.encode(credentials.email + ':' + credentials.password);
return $http.post('/api/auth/signin', {skipAuthorization: true});
-Configure the http interceptors to send the token to the server on every request and store the token on the response. If a refreshed token is received this one must be stored.
// Config HTTP Interceptors
angular.module('auth').config(['$httpProvider',
function($httpProvider) {
// Set the httpProvider interceptor
$httpProvider.interceptors.push(['$q', '$location', 'localStorageService', 'jwtHelper', '$injector',
function($q, $location, localStorageService, jwtHelper, $injector) {
return {
request: function(config) {
var token = localStorageService.get('authToken');
config.headers = config.headers || {};
if (token && !jwtHelper.isTokenExpired(token)) {
config.headers.Authorization = 'Bearer ' + token;
}
return config;
},
requestError: function(rejection) {
return $q.reject(rejection);
},
response: function(response) {
//JWT Token: If the token is a valid JWT token, new or refreshed, save it in the localStorage
var Authentication = $injector.get('Authentication'),
storagedToken = localStorageService.get('authToken'),
receivedToken = response.headers('Authorization');
if(receivedToken) {
receivedToken = Authentication.fetchJwt(receivedToken);
}
if(receivedToken && !jwtHelper.isTokenExpired(receivedToken) && (storagedToken !== receivedToken)) {
//Save Auth token to local storage
localStorageService.set('authToken', receivedToken);
}
return response;
},
responseError: function(rejection) {
var Authentication = $injector.get('Authentication');
switch (rejection.status) {
case 401:
// Deauthenticate the global user
Authentication.signout();
break;
case 403:
// Add unauthorized behaviour
break;
}
return $q.reject(rejection);
}
};
}
]);
}
]);

Resources