AngularJS - Setting default http headers dynamically - angularjs

To overcome csrf attack, I have to send in csrf-token value in a header for every request by picking in the value from cookie as described here. Since this is to be done at every request, I am setting the default headers for $http in the main module's run function.
Now, If a new tab is opened for the same website, a new csrf token (in cookie) is issued by the server. Since the run function is run only once, the default header for csrf will be old one (for old tab), while the new csrf cookie will be sent to server, resulting in csrf-mismatch.
How to overcome this at a global level?
I want somehow to create a function which will be run everytime the $http is called, so that then I'll override the default headers.
Note: I do not want to set this header value for every $http request.
(Not that I think that it's relevant, but I'm using ui-router)
Edit
This is not just limited to csrf-token, I want to set some other headers too based on the logged in user, which has to be done dynamically (say when one user logs in, and logs out, then another user logs in).

you need to use http interceptor to do this on every request. read more about http interceptors here
below is one such example
module.factory('xsrfTokenInterceptor', function ($q, $http) {
return {
'response': function (response) {
var cookies = response.headers("Set-Cookie");
var token = someCrazyParsing(cookies);
$http.defaults.headers.common["X-CSRFToken"]=token;
return response || $q.when(response);
}
};
});
module.config(function($httpProvider){
$httpProvider.interceptors.push('xsrfTokenInterceptor')
})

How about headers $http(config) parameter.
$scope.getWithHeader = function(){
$http({
method: 'GET',
url: 'http://fiddle.jshell.net',
headers: {
'CustomHeader': 'HelloWorld'
}
}).success(function(){
console.log("success");
});
};
sample code on jsFiddle

Related

How to 'add' cookie only for angular.http request

I need to emulate some state in my developer utility, and for it I need to pass some special cookie to the http request which made via angular $http module.
Code for making http request looks simple:
if (condition){
var headers = getHeaders();
if (headers !== 'undefined'){
config['headers'] = headers;
}
}
return $http(config);
So looks like I should add some field to the this config. But I can't find any related data about this in $http docs.
I do not want to set cookie 'to the browser' becase I want to pass it only for some several requests performed asynchronously.
Is it real to nmake it with angular.js?

angularjs clearing the cache from a particular request

All the http requests I'm making are cached by default. Now, how do I clear the cache of a particular request?
Here is a situation to explain better. I have a REST API that sends two different kinds of data based on the authentication. Whenever the User has authenticated I need to clear the old data and make new request with the authentication. My controller gets refreshed but the API call is not being made as the call is already cached. It returns the old data.
You can us a custom cache object using Angular's built-in $cacheFactory
E.g
// cache the HTTP response
$http.get('myurl',{
cache: true
}
// this object can now be retrieved using $cacheFactory
var httpCache = $cacheFactory('$http');
// to remove the value from the cache, get the default $http cache, call the remove function and pass in the url
var httpCache = $cacheFactory.get('$http');
httpCache.remove('myurl');
Telling our $http requests to make requests through our own custom cache is simple. Instead of passing a boolean true with the request, we can pass the instance of the cache.
var myCache = $cacheFactory.get('myCache');
$http({
method: 'GET',
url: '/api/users.json',
cache: myCache
});
// Or, using the .get helper
$http.get('/api/users.json', {
cache: myCache
});
Now, instead of using the default cache, $http will use our custom cache.

AngularJS continues to perform preflight request even without application/json content type

At this point I am at a complete loss. I have searched the SO and the documentation and it says that Angular's $http will not perform an OPTION request if you put anything but content-type: application/json
I have the code below:
$scope.login = function(){
authFactory.login($scope.username, $scope.password).success(function(){
alert("here");
}).error(function(){
alert("ERROR");
});
app.factory('authFactory', ['$http', function ($http) {
var factory = {};
factory.login = function (username, password) {
var data = new Object();
data.username = username;
data.password = password;
return $http({
method: 'POST',
url: wsURL + 'login',
data: data,
headers: {
'Content-Type': 'x-www-form-urlencoded'
}});
}
return factory;
}]);
I keep getting an OPTIONS request and I cannot do anything about it.
My server is an embedded Jetty who is lacking an web.xml so I had to go at great lengths to configure it. At some point I seemed to work and not send the options request but out of the blue (without changing anything it stopped again).
Any help?
After all, SoluableNonagon was right that because I was sending a custom header I could not avoid the preflight request to Jetty. However, after searching for a way to make it work.
I am posting here for helping anyone else with similar needs.
The way to make this work with Jetty is to configure the CrossOriginFilter appropriately so as to not chain the request to your application if you do not want this (as was my case). The way to do this is below.
FilterHolder holder = new FilterHolder(new CrossOriginFilter());
holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_METHODS_HEADER, "GET,POST,HEAD,OPTIONS");
holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true");
holder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "*");
holder.setInitParameter(CrossOriginFilter.CHAIN_PREFLIGHT_PARAM, "false");
holder.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_EXPOSE_HEADERS_HEADER, "true");
holder.setInitParameter(CrossOriginFilter.EXPOSED_HEADERS_PARAM, "X-AUTH-TOKEN");
Notice the statements responsible for allowing the header to pass and stop chaining it to the application are holder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "*"); and holder.setInitParameter(CrossOriginFilter.CHAIN_PREFLIGHT_PARAM, "false");.
The last two statements in the codeblock above are responsible for allowing you to retrieve the token from the custom header. Not entirely relevant to the question but will definitely be needed.

How to setup XSRF protection in angular js?

I am developing an application using angularJs, resources and jersey rest api's. And I want to implement xsrf protection in my project. Please suggest a better example. I got one example here, but it uses ColdFusion. http://www.bennadel.com/blog/2568-Preventing-Cross-Site-Request-Forgery-CSRF-XSRF-With-AngularJS-And-ColdFusion.htm
Different from given example, you need to do 2 things:
When the main page gets loaded once the user logs in, you need to set a session cookie with name XSRF-COOKIE. Then AngularJS will do the rest by appending a header to every request as stated in documentation (1)
You need to validate every call to your rest API in back-end (for example with an interceptor) by comparing the token in cookie and the one in header. The logic is described on the page you referenced
(1) To take advantage of this, your server needs to set a token in a JavaScript readable session cookie called XSRF-TOKEN on the first HTTP GET request. CSRF Protection section in Documentation
Incase this is your code in jsp/ html page which sets the header and token:
<meta name="_csrf" content="${_csrf.token}"/>
<meta name="_csrf_header" content="${_csrf.headerName}"/>
You can configure the csrf headers for all ajax requests as flollows:
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
angular.module("app", [])
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.common[header] = token;
}]);
And then your http request code will go as follows:
$http({
url: "loadMyData.htm",
method: "POST",
}).success(function(data)
{
console.log(data);
})
create interceptor with below command.
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const cookie = this.cookieService.get('XSRF-TOKEN');
request = request.clone({
headers: new HttpHeaders({
'XSRF-TOKEN': cookie,
}),
withCredentials: true
});
return next.handle(request);
}

How do I remove the default headers just for specific XHR requests in AngularJS?

99% of my ajax calls need a specific "X-API-TOKEN" to authenticate and communicate with my Rails REST API. But I'm also making a call to one thrid party API and I keep getting an error saying "Request header field X-API-TOKEN is not allowed by Access-Control-Allow-Headers."
Everything works fine if I delte the header right before the call, and a work around would be to delete and then re-add after the call, but is there an easier way than this:
apiToken = $http.defaults.headers.common["X-API-TOKEN"]
delete $http.defaults.headers.common["X-API-TOKEN"]
$http(
method: "GET"
url: 'http://...}}'
).success((data, status, headers, config) ->
).error (data, status, headers, config) ->
$http.defaults.headers.common["X-API-TOKEN"] = apiToken
Set the desire header/headers to undefined like this, then it will not affect the global settings.
$http( {
method: 'GET',
url: 'someurl',
headers: {
'X-API-TOKEN': undefined
}
}
)
The $http service config object allows you to override the http header send for a specific request. See config property headers.
This can take a list of headers or a function that return a list of headers. So for the non auth header request make a copy of the default headers remove the header you dont require and then make the request. You can store this for later use.
See $http documentation

Resources