Angular js don't send custom header while preflight request is made - angularjs

I have following code
angular.module('myApp.Utils',[])
.factory('AuthInterceptor', function($q, $location) {
return {
request: function(config) {
config.headers = config.headers || {};
if (window.localStorage.token) {
config.headers.Authorization = 'Bearer ' + window.localStorage.token;
}
config.headers["Content-Type"] = 'application/x-www-form-urlencoded';
return config || $q.when(config);
},
response: function(response) {
if (response.status === 401) {
//redirect user to login page
$location.url('/login');
}
return response || $q.when(response);
}
};
})
.config(function($httpProvider) {
$httpProvider.interceptors.push('AuthInterceptor');
});
If we have value for token key in localStorage, it adds Authorization Header to every ajax calls made.
Problem
It works well if there is no token (No header sent). But when token exist in localstorage and I make an API call, I get following error
Response for preflight has invalid HTTP status code 404
After research i found that, the browser makes preflight request (OPTIONS request), before making a real request.
I also found that we cannot send custom Headers in preflight request. So is there anyway to fix this, to send custom Headers only when making a real request.?
I have tried adding following in .htaccess of the server that serves API calls
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "Content-Type, Authorization, Origin, X-Requested-With"
Header always set Access-Control-Allow-Methods "GET,POST,HEAD,DELETE,PUT,OPTIONS"
</IfModule>

I have found answer myself.
Its not related to angular or .htaccess thing. Its more related to the server side.
When CORS request is made, the browser makes a test(preflight) request to see if everything is ok, then only it makes actual request.
Following code in the API call solved the problem.
<?php
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: X-Requested-With, Authorization');
exit;
}

Related

403 forbidden Rest API (node js) in Angular js1

I am calling nodeJS REST API running on different localhost into an angular app,
in postman I get the expected result. but in angular application it is falling due to 403 error, It is happening because of preflight( Response for preflight has invalid HTTP status code 403). I tried to remove some default headers using $httpprovider and also tried to use proper server name instead of wildcard(*) in access-control-allow-region nothing worked.Looking for help!
There is no Authentication for preflight requests.
Posting my req-respo snap
By handling OPTIONS request at server side i am able to solve the problem,
This post solved my problem
By adding following line of code
app.use(function (req,res,next){
if (req.method === 'OPTIONS') {
console.log('!OPTIONS');
var headers = {};
// IE8 does not allow domains to be specified, just the *
// headers["Access-Control-Allow-Origin"] = req.headers.origin;
headers["Access-Control-Allow-Origin"] = "*";
headers["Access-Control-Allow-Methods"] = "POST, GET, PUT, DELETE, OPTIONS";
headers["Access-Control-Allow-Credentials"] = false;
headers["Access-Control-Max-Age"] = '86400'; // 24 hours
headers["Access-Control-Allow-Headers"] = "X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept";
res.writeHead(200, headers);
res.end();
} else {
//...
other requests
}
});

CORS Issue in Web Console (angular js)

I have a developed a web console in angular JS in which I am using post and put methods and making HTTP requests in which I send json and calling a WSO2 REST API to get response accordingly. Its running on server but I am facing CORS problem. I have add add extension in browser and enable it otherwise I get following error.
XMLHttpRequest cannot load http://127.197.200.100:8000/ManagementAPI/createuser. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.197.200.100:8000' is therefore not allowed access.
This is how I am sending request
CreateUser: function(adata) {
var config = {
headers :{
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}
var promise = $http.post(213.187.243.177:8283/ManagementAPI/createuser,adata,config).then(function (response) {
return [response.status,response.data];
},function (response) {
console.log("Error Returned" + response.status);
return [response.status,response.data];
});
return promise;
},
I have tried ThisLink for solution but did not work. Need a solution for accessing it without CORS.
Set headers in back end for avoiding CORS issues .
Sample code in php is shown in below
if (isset($_SERVER['HTTP_ORIGIN'])) {
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 86400'); // cache for 1 day
}
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
exit(0);
}

Why does Angular send Http Request Method: Options before POST?

I'm using Angular Dart V1 for a front end framework
I am using shelf && shelf router for a backend API
I'm trying to migrate some old get requests to accept Post Data
Old request:
Future fetchRoutes(FlightPostParamsVO params) async {
return _http.get(BASE + 'routes').then(handleRoutes);
}
New Request
Future fetchRoutes(FlightPostParamsVO params) async {
Map post = params.toPostable();
return _http.post(BASE + 'routes', post ).then(handleRoutes);
}
I'm setting the CORS headers in a generic response for all calls as its strictly a JSON API:
Future<Response> makeResponse( json ) async {
var response = new Response.ok( json, headers: {'content-type': 'text/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': "Origin, X-Requested-With, Content-Type, Accept",
'Access-Control-Allow-Methods': "POST, GET, OPTIONS"} );
return response;
}
I get a 404 an the following output:
OPTIONS http://localhost:1234/tickets/routes 404 (Not Found)
(index):1 XMLHttpRequest cannot load http://localhost:1234/tickets/routes. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 404.
When i inspect the network traffic - all my GET request DO HAVE the correct headers
When i inspect the network traffic - my POST call is lead bya request with a method set as OPTIONS - this call does not have the headers included.
My POST route handler never gets called
Router
Router airRouter = router();
Router tickets = airRouter.child('/tickets');
tickets.add('/cities', ['GET'], controller.handleCitites);
tickets.add('/times', ['GET'], controller.handleTimes);
tickets.add('/routes', ['POST'], controller.handleRoutes);
tickets.add('/{id}/tickets/', ['GET'], controller.handleTickets);
io.serve(airRouter.handler, 'localhost', 1234);
Fix Symptom:
tickets.add('/routes', ['OPTIONS'], controller.handleRoutes);
Question: Why is the HTTP Request sending a Request Method:OPTIONS before each POST, and whats the proper way only call POST?
That is not angular. Its the browser. The first request of method OPTION is to test for CORS header to make sure the browser is allowed to post.
Solution:
http://thomaslockerambling.blogspot.com/2014/10/shelf-middleware-adding-cors-headers.html
Create a CORS Object and append to header
Intercept an Call to OPTIONS
Response with status code 200 OK

AngularJS $http GET method to backend server: Request Method:OPTIONS 405

$http GET request to a clojure backend, to get a list of services.
I get is an OPTIONS request (???), which gets a 405 response...
<code>
var config = {headers: {
'Authorization': 'Bearer d2VudHdvYW5nZV9tZQ',
"X-Testing" : "testing"
}
};
$http.get(SERVER.MESSAGE_SERVICES, config)
.success(function(successCallback) {
$scope.services = successCallback;
})
.error(function(errorCallback) {
console.log(errorCallback.toString);
}).
finally(function() {
console.log("Message services rest call");
});
</code>
**clojure backend**:
<code>
headers {"Access-Control-Allow-Origin" "*"
"Access-Control-Allow-Headers" "X-Requested-With, Origin,Content-Type, Accept"
"Access-Control-Allow-Methods" "GET, POST, OPTIONS"}
</code>
There is no problem that AngularJS sends an OPTIONS request, that is because CORS standards force to do so. Be sure that the server is configured to allow a GET method.
Yes as raso suggested this problem is because of Cross Origin Resource Sharing(CORS). The same old privacy policy prevents JS/ angularJS from making requests across domain boundaries.
Configure server to allow cross domain requests.
Or
If you are using Chrome than you can use this extension to surpass this problem.

Angularjs handling 401 Errors application wide

I am struggling a little bit with handling 401 errors application wide.
Some other posts where not really helping me:
Angularjs - handling 401's for entire app
401 unauthorized error handling in AngularJS
I have to send an authentication token, if it is defined on every request, thats why I need a request part in the Interceptor.
My current approach looks like:
module.factory('authInterceptor', function ($rootScope, $q, $window, $location) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
else{
console.log("authInterceptor: No Token to send")
}
return config;
},
response: function (response) {
if (response.status == 401) {
console.log("No Logged In");
$location.path('/login');
}
return response || $q.when(response);
},
responseError: function(rejection){
var defer = $q.defer();
if(rejection.status == 401){
console.log("401 Rejection");
console.dir(rejection);
}
defer.reject(rejection);
return defer.promise;
}
};
});
As far as my debugging goes if a 401 happens after request, it will be handled in the repsonse function. Which itself gives way a promise to the original caller.
If i comment out $q.when(response) and only return the repsonse there is no change.
Response is called even before the original caller gets .error
Thx for any ideas. Hopefully I am not to far away from a solution.
I had the same issue, and in my case the problem was that I was adding the CORS headers as an after filter in the response, which meant that they weren't being sent when a 401 was issued.
Not sure what type of server you are using, but this is the rails version that works for me (changing it to a before_filter:
before_filter :allow_cors
def allow_cors
headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, PUT, GET, OPTIONS'
headers['Access-Control-Allow-Headers'] = 'Accept, Cache-Control, Referer, User-Agent, Origin, X-Requested-With, X-Prototype-Version, Content-Type, accept, autho
headers['Access-Control-Allow-Credentials'] = 'true'
headers['Access-Control-Request-Method'] = '*'
headers['Access-Control-Max-Age'] = '1728000'
end
(Clearly these are quite permissive settings, so please adjust them before using it in production)
They way I've managed to find this out was by testing the request locally with CURL, so this might help you:
curl -H "Origin: http://example.com" --verbose http://localhost:3000/
This way you will be able to see if the headers are being returned correctly even when the request is not authorized.
Your approach is good.
I think you don't need the "response" interceptor, only "request" to inject token and "responseError" to handle 401 response error :
return {
'responseError': function(response) {
if (response && response.status === 401) {
//DO WHAT YOU WANT HERE
console.log("There was a 401 error");
}
return $q.reject(response);
},
'request': function(config) {
config.headers = config.headers || {};
// ADD YOUR HEADER HERE
return config || $q.when(config);
}
};
#frankmt thanks a lot! Not enough rep to upvote or comment your solution, anyways it is exactly what I had missed. With Express and CORS it would be..
// THE CORS BLOCK HAS TO GO BEFORE THE JWT BLOCK
app.options('*', cors());
app.use(cors());
//protect routes with JWT - Token based auth
var secret = 'env.SECRET';
var publicPaths = [ '/apply', '/login'];
app.use('/', expressJwt({secret: secret}).unless({path: publicPaths}));
If you have Devise in the stack; it's most likely failing because Warden takes precedence over anything else. The headers won't be inserted; even though you use a before_action instead of after_action.
Check out this question instead: ttp://stackoverflow.com/questions/11177079/how-to-send-cors-headers-with-devise-if-user-not-authorized-401-response

Resources