NodeJS proxy not working as intended - angularjs

The current route of the request originates on localhost:3001, goes through a proxy running on that same localhost at localhost:3001/proxy, where the request is then routed to the Salesforce instance. The proxy is made using ExpressJS and the client side app is made using AngularJS. Note: I did remember to tag my security token at the end of my password (Salesforce API requirement), although when using cURL, this doesn't seem to be necessary. Here are a series of HTTP traces that will hopefully provide some clues:
HTTP Request Log from Angular.JS App:
POST /proxy HTTP/1.1
Host: localhost:3001
Connection: keep-alive
Content-Length: 234
Pragma: no-cache
Cache-Control: no-cache
X-User-Agent: salesforce-toolkit-rest-javascript/v29.0
Origin: http://localhost:3001
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: application/json, text/plain, */*
SalesforceProxy-Endpoint: https://uniquename.salesforce.com/services/oauth2/token
Referer: http://localhost:3001/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: liveagent_oref=; liveagent_ptid=3c69c2f9-139d-4439-ba6c-fd8d9dcae101; liveagent_vc=5
grant_type=password&client_id=3MVGxyzxyzxyzxyz&client_secret=99889988&username=first.last%40email.com&password=pswdwACYodaYfHs
400 Bad Request
Object {error_description: "grant type not supported", error: "unsupported_grant_type"}
Relevant Express.JS code used for proxy routing:
app.all('/proxy', function(req, res) {
var url = req.header('SalesforceProxy-Endpoint');
console.log(req.body); //prints all form data variables in JSON format
console.log(res.body); //undefined
request({url: url}).pipe(res).on('error', function(error){
//I think I may need to pipe more information using request?
console.log(error);
});
});
Request details using cURL:
curl -v https://uniquename.salesforce.com/services/oauth2/token
-d "grant_type=password" -d "client_id=3MVGxyzxyzxyzxyz"
-d "client_secret=99889988" -d "username=jfirst.last#email.com" -d "password=pswd"
> POST /services/oauth2/token HTTP/1.1
> User-Agent: curl/7.41.0
> Host: uniquename.salesforce.com
> Accept: */*
> Content-Length: 207
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 207 out of 207 bytes
< HTTP/1.1 200 OK
< Date: Wed, 29 Jul 2015 06:04:55 GMT
< Set-Cookie: BrowserId=auu1mgvHSMS1EedDEduz8Q;Path=/;Domain=.salesforce.com;Exp
ires=Sun, 27-Sep-2015 06:04:55 GMT
< Expires: Thu, 01 Jan 1970 00:00:00 GMT
< Pragma: no-cache
< Cache-Control: no-cache, no-store
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
<
{
"id":"https://test.salesforce.com/id/05390530530",
"issued_at":"1438132525896197",
"token_type":"Bearer",
"instance_url":"https://uniquename.salesforce.com",
"signature":"blahblah",
"access_token":"XXXXXXXXXXXXXXXXX"
}
* Connection #0 to
host uniquename.salesforce.com left intact
As you can see, I get back a valid response from the cURL request. I suspect something is wrong with the proxy, as it may not be forwarding all the form data to Salesforce, but I'm not sure how to debug that in Express.JS. The reason I suspect this is because if I try curl https://uniquename.salesforce.com/services/oauth2/token it returns the same unsupported_grant_type error.

I finally got this working by switching to use the cors-anywhere proxy. I deploy my AngularJS app on port 8080, and the proxy on port 3001. My packages are managed using npm and grunt. Here is the code for the proxy:
var host = 'localhost';
var port = 3001;
var cors_proxy = require('cors-anywhere');
cors_proxy.createServer().listen(port, host, function() {
console.log('CORS proxy running on ' + host + ':' + port);
});
And here is how I'm making the HTTP request in AngularJS (you have to fill in your own credentials in the data object):
var login = {
method: 'POST',
url: 'http://localhost:3001/https://login.salesforce.com/services/oauth2/token',
data: 'grant_type=password&client_id='+encodeURIComponent(CLIENT_ID)+'&client_secret='+encodeURIComponent(CLIENT_SECRET)+'&username='+encodeURIComponent(EMAIL)+'&password='+encodeURIComponent(PASSWORD+USER_SECURITY_TOKEN),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*'
}
};
$http(login).success(function(response){
console.log(response);
})
.error( function(response, status){
console.log(response);
console.log("Status: " + status);
});
You can run the proxy with the node server.js command, and run the AngularJS app with grunt. I hope this helps someone out, this was a tough problem to solve.

I don't think you're proxying everything in the HTTP request. I've included some code below that will pass the request method and the request headers to your endpoint.. Also try using the 'request-debug' library so you can compare the proxy HTTP request vs your curl request and look for differences
var express = require('express');
var app = express();
var request = require('request');
require('request-debug')(request);
app.all('/proxy', function(req, res) {
var url = req.header('SalesforceProxy-Endpoint');
var options = {
url: url,
method: req.method,
headers: req.headers
}
request(options).pipe(res).on('error', function (error, response, body) {
if (!error && response.statusCode == 200) {
//TODO: do something useful with the response
} else {
console.log('ERROR: ' + error);
}
});
});

Related

Fail to fetch internal api data in nextjs app deployed with amplify and AWS

My Nextjs app is deployed on AWS x Amplify at https://<example.com> but the js console indicates it fails to fetch data from the internal api.
The endpoint is defined in this function in a Flux Store object.
_getAssets = async () => {
try {
const response = await fetch(`${process.env.NEXT_PUBLIC_API}/api/v1/assets`, {
method: 'get',
headers: {
'Authorization': `Basic ${process.env.NEXT_PUBLIC_API_TOKEN}`,
}
})
const assetsCall = await response.json()
return assetsCall.data
} catch(ex) {
console.log(ex)
return []
}
}
In my environment:
NEXT_PUBLIC_API=<example.com>
NEXT_PUBLIC_API_TOKEN=12345
The build script is "next build && next export"
The api call produces error 404.
In js console:
**GENERAL**
Request URL: <example.com>/api/v1/assets
Request Method: GET
Status Code: 404
Remote Address: 13.35.13.120:443
Referrer Policy: strict-origin-when-cross-origin
**RESPONSE HEADERS**
age: 5524
cache-control: public, max-age=0, s-maxage=2678400, must-revalidate
content-encoding: gzip
content-type: text/html
date: Tue, 15 Mar 2022 05:31:29 GMT
etag: W/"a396cb2a54d64f73533333bfa2da1e6d"
last-modified: Tue, 15 Mar 2022 05:24:37 GMT
server: AmazonS3
vary: Accept-Encoding
via: 1.1 0b3572829f6f42309f3adfa694398770.cloudfront.net (CloudFront), 1.1 fb176da9df72832dd488674f28c0a880.cloudfront.net (CloudFront)
x-amz-cf-id: g-I0JZ1hTHIfaL0yfGTX5c42i6wkxdRljRgRCD9Ei87lRb4KNsJo-w==
x-amz-cf-pop: SIN5-C1
x-amz-cf-pop: SIN5-C1
x-cache: Error from cloudfront
**REQUEST HEADERS**
:authority: <example.com>
:method: GET
:path: /api/v1/assets
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-GB,en-US;q=0.9,en;q=0.8
authorization: Basic 12345
referer: https://<example.com>/vest
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-origin
sec-gpc: 1
user-agent: Mozilla/5.0 <blabla>
My questions:
Is it correct to define NEXT_PUBLIC_API as <example.com> (the frontend URL) in my environmnent, or should the api call another URL?
Why can't the app fetch data from the api? I haven't defined custom headers in customHttp.yml, do i need to write something in this file?

React not sending back httpOnly & CSRF cookies back to Flask REST API, even with options included (fetch API)

I'm building a REST API with Flask (using Flask-RESTful and Flask-JWT-Extended) and a front end React application that consumes its data.
To log users in, after getting their credentials through the login endpoint, the server sends back an access JWT and a refresh JWT (both in the form of httpOnly cookies) and a CSRF cookie for each JWT, the idea being that for further requests to any API endpoint the client has to send the access JWT and the CSRF cookies.
As I understand, those cookies should be sent automatically, but in reality they're not being sent. The login works fine (I receive the 4 cookies I expect), but on further requests my React front end is not sending the cookies back, even including the authorization: 'include' and credentials: 'include' options in the request header.
I think it's worth to note that the React server runs on port 3000 and my Flask API on port 5000. I think it may cause a problem, but its just a hunch as I don't know how it might affect the communication between the two.
These are the response headers for the login endpoint (which works fine):
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 29
Set-Cookie: access_token_cookie=<very_long_access_JWT>; HttpOnly; Path=/
Set-Cookie: csrf_access_token=<csrf_access_token>; Path=/
Set-Cookie: refresh_token_cookie= <very_long_refresh_JWT>; HttpOnly; Path=/
Set-Cookie: csrf_refresh_token= <csrf_refresh_token>; Path=/
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin
Server: Werkzeug/2.0.2 Python/3.10.2
Date: Fri, 18 Mar 2022 21:07:03 GMT
These are the request headers for trying to send a POST request to the test endpoint:
POST /api/test HTTP/1.1
Host: 127.0.0.1:5000
Connection: keep-alive
Content-Length: 0
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: "Chromium";v="98", " Not A;Brand";v="99"
authorization: include
DNT: 1
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.136 Safari/537.36
credentials: include
sec-ch-ua-platform: "Linux"
Accept: */*
Origin: http://localhost:3000
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,es;q=0.8
And this is a "condensed" version of the fetch function that I use on every View on my React application.In reality, the fetchResource() function is saved in its own module and is imported and called by differente Views as needed. I have tested this function before to fetch data without login in and it works.
/**
* Multipurpose fetch function
* #param {string} queryURL URL string to fetch from.
* #param {Object} options request options. Defaults to null
* #returns {Object} returns jsonified data if fetch was successfull, error object if not
*/
const fetchResource = async (queryURL, options = null) => {
try {
const response = await fetch(queryURL, options);
const data = await response.json();
if (!response.ok) {
return { code: response.status, data };
}
return data;
} catch (error) {
return `Looks like there was a problem: ${error}`;
}
};
fetchResource('http://127.0.0.1:5000/api/test', {
method: 'POST',
headers: {
authorization: 'include',
credentials: 'include'
}
});
What could be causing this issue? I'm completely new to cookies and I'm at a loss here.

Browser not storing session cookie from React XHR request from express-sessions ** updated config

I am using a React frontend to log into a nodejs server running express-session. Frontend is running on localhost:3000, server is on localhost:5000.
Everything is working properly using postman from localhost (session cookie is sent from server when user is properly authenticated and received/stored by postman. Subsequent postman api request to different path on server uses the session cookie and correctly retrieves the data it should based on the session contents). I can also is login using the browser directly to the server (http://localhost:5000/api/authenticate). The server generates the session, sends the cookie to the browser and it stores the cookie locally.
What doesn't work is when I make the api request from within the React app. The server is returning the session cookie but the browser is not storing it. After researching this for the last few days (there are a lot of questions on this general subject), it seems to be an issue with cross site request but I can't seem to find the right set of app and server settings to get it working properly. The cookie is being sent by the server but the browser won't store it when the request from the app.
*** after some additional troubleshooting and research, I've made some updates. My initial XHR request requires a pre-flight and the request and response headers appear to be correct now but still no cookie being stored in browser. More details below the setup ****
Server Setup
var corsOptions = {
origin: 'http://localhost:3000',
credentials: true
};
app.options('*', cors(corsOptions)) // for pre-flight
app.use(cors(corsOptions));
app.use(session({
genid: (req) => {
console.log('Inside the session middleware');
console.log(req.sessionID);
return uuidv4();
},
store: new FileStore(),
secret: 'abc987',
resave: false,
saveUninitialized: true,
cookie: { httpOnly: false, sameSite: 'Lax', hostOnly: false }
}));
app.use( bodyParser.json() );
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, withCredentials, credentials');
next();
});
app.post('/api/authenticate', function(req, res) {
const usernameLower = req.body.username.toLowerCase();
const passwordHash = md5(req.body.password);
connection.query('select USERID from USERS where LOWER(USERNAME)=? && PASSWORD=? ', [usernameLower, passwordHash], function (error, results, fields) {
if (error) {
console.log(error);
req.session.destroy();
res.status(500)
.json({
error: 'Internal error please try again'
});
} else if (results[0]) {
const userId = results[0].USERID;
// setup session data
mySession = req.session;
mySession.user = {};
mySession.user.userId = userId;
res.json(mySession.user);
} else {
console.log('auth failed');
req.session.destroy();
res.status(401)
.json({
error: 'Incorrect email or password'
});
}
});
});
Client setup -- the request is triggered by clicking a submit button in a form
handleSubmit(event) {
event.preventDefault();
axios.defaults.withCreditials = true;
axios.defaults.credentials = 'include';
axios({
credentials: 'include',
method: 'post',
url: 'http://localhost:5000/api/authenticate/',
headers: {'Content-Type': 'application/json' },
data: {
username: this.state.username,
password: this.state.password
}
})
.then((response) => {
if (response.status === 200) {
this.props.setLoggedIn(true);
console.log('userId: '+response.data.userId);
} else {
console.log("login error");
}
})
.catch(error => console.log(error))
}
Below is the response cookie sent to the browser but the browser is not storing it.
{"connect.sid":{"path":"/","samesite":"Lax","value":"s:447935ac-fc08-47c6-9b66-4fa30b355021.Yo5H3XVz3Ux3GjTPVhy8i2ZPJm2RM2RzUnznxU9wBvo"}}
Request headers from XHR request (pre-flight):
OPTIONS /api/authenticate/ HTTP/1.1
Host: localhost:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Referer: http://localhost:3000/
Origin: http://localhost:3000
DNT: 1
Connection: keep-alive
Pre-flight server response headers
HTTP/1.1 204 No Content
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin, Access-Control-Request-Headers
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
Access-Control-Allow-Headers: content-type
Content-Length: 0
Date: Fri, 10 Jul 2020 21:35:05 GMT
Connection: keep-alive
POST request header
POST /api/authenticate/ HTTP/1.1
Host: localhost:5000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
Content-Length: 45
Origin: http://localhost:3000
DNT: 1
Connection: keep-alive
Referer: http://localhost:3000/
Server response headers
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:3000
Vary: Origin
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Content-Type: application/json; charset=utf-8
Content-Length: 95
ETag: W/"5f-Iu5VYnDYPKfn7WPrRi2d2Q168ds"
Set-Cookie: connect.sid=s%3A447935ac-fc08-47c6-9b66-4fa30b355021.Yo5H3XVz3Ux3GjTPVhy8i2ZPJm2RM2RzUnznxU9wBvo; Path=/; SameSite=Lax
Date: Fri, 10 Jul 2020 21:35:05 GMT
Connection: keep-alive
I used the "Will it CORS" tool at https://httptoolkit.tech/will-it-cors/ and my request/response headers all seem to be correct but still no cookie stored.
Pre-flight request contains the correct origin
Pre-flight response contains the correct allow-origin and allow-credentials
POST request contains the correct origin and allow-credentials
POST response contains the correct
Appreciate any help to unravel this....
I solved my issues and wanted to post the solution in case others come across this.
To recap, the backend server is nodejs using express. The following setup allows the front-end to accept the cookies which were created on the nodejs server.
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "https://frontendserverdomain.com:3000"); // update to match the domain you will make the request from
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Credentials", true); // allows cookie to be sent
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, HEAD, DELETE"); // you must specify the methods used with credentials. "*" will not work.
next();
});
The front-end app is based on React and uses axios to make http request. It is hosted at "https://frontendserverdomain.com:3000" which is added to the "Access-Control-Allow-Origin" header in the nodejs setup (see above).
On the front-end, Axios needs the "withCreditials" setting applied.
axios.defaults.withCredentials = true;
With these settings, your app will be able to exchange cookies with the back-end server.
One gotcha for me getting CORS working was to make sure the front-end host is properly added to the back-end servers header "Access-Control-Allow-Origin". This includes the port number if it's specified in your URL when accessing the front-end.
Inn terms of cookie exchange, the "Access-Control-Allow-Credentials" and "Access-Control-Allow-Methods" headers must be set correctly as shown above. Using a wildcard on "Access-Control-Allow-Methods" will not work.
This does not look right:
axios.defaults.headers.common = {
credentials: "include",
withCredentials: true
}
There are no such request headers. Instead credentials is controlled via XHR request.
Use this instead to make sure your client accepts cookies:
axios.defaults.withCredentials = true;

CSRF mismatch when POSTing to sails backend from Angular JS

In angular, I obtain a CSRF token like this:
// Get CSRF token and set as header
var csrfRequest = Auth.getCSRF().then(function(data){
console.log(data.data._csrf);
$rootScope.csrf = data.data._csrf;
});
Which logs the new token to the console (this works fine).
Then, I try to login to a sails.js api. Here's the request:
POST /auth/login HTTP/1.1
Host: localhost:1337
Connection: keep-alive
Content-Length: 108
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/plain, */*
Origin: http://localhost
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: http://localhost/sails-front/src/login/
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
Request Payloadview parsed
{"email":"myemail#email.com","password":"mypass","_csrf":"PIlVO7S362OroPGBSG0X1vW2FydkP9VhK8cMk="}
The _csrf field is the same as that which was received in the getCSRF call.
Yet I get the response 'CSRF mismatch'. However, when I try the exact same thing with Postman, it works fine (so I don't think it's a problem with the sails server).
Here's the login code in angular. In the controller:
$scope.login = function() {
Auth.login({
email: $scope.email,
password: $scope.password,
_csrf: $rootScope.csrf
},
function(res) {
$state.go('app.home');
},
function(err) {
$rootScope.error = "Failed to login";
});
};
And the Auth service:
/*********************************
* login
******************************** */
function login(user, success, error) {
$http.post(API_BASE_URL + 'auth/login', user).success(function(user){
changeUser(user);
success(user);
}).error(error);
}
You posted your full request, and the answer is hidden there in plain sight--not by looking at what is being sent, but what is being omitted: namely, the cookie. The CSRF token is valid for a single Sails session, but you are neglecting to send the cookie with your AJAX request, so Sails has no idea which session the CSRF token you're sending is for.
To tell Angular to send cookies with your request, use the withCredentials setting:
$http.post(API_BASE_URL + 'auth/login', user, {withCredentials: true})

AngularJS $http seems to not respond correctly when I am using CORS

I have an AngularJS application. It sends out requests to another server for data and so there's an OPTIONS request goes out with every $HTTP call.
When I check with fiddler there are two calls. The Options that always returns a 200 OK and then the data call.
However when I check the $HTTP it seems that it's getting the first request ( the options request ) and not getting the second request the one with real data.
Can someone point me in the right direction with this?
Here's one example of the code that is not responding correctly:
.factory('isUsernameAvailable', function (appConstant, $q, $http) {
return function (username) {
var deferred = $q.defer();
// if (!angular.isDefined(username) || username == null || username == "" || username.length < 6 ) return deferred.resolve();
var url = appConstant.baseUrl + '/api/user/existsByName';
$http({
url: url,
method: "PUT",
data: {
userName: username
}
}).then(function (data) {
// Found the user, therefore not unique.
deferred.reject("User name is taken");
}, function (data) {
// User not found, therefore unique!
deferred.resolve();
});
return deferred.promise;
}
})
I expect it to be returning as success or failure depending on if it finds the username. But in this case it always responds as a fail/error.
Here are the requests being made:
OPTIONS http://localhost:3048/api/user/existsByName HTTP/1.1
Host: localhost:3048
Connection: keep-alive
Access-Control-Request-Method: PUT
Origin: http://localhost:2757
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Access-Control-Request-Headers: accept, authorization, content-type
Accept: */*
Referer: http://localhost:2757/Auth/register
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
giving:
HTTP/1.1 200 OK
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: http://localhost:2757
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: content-type
X-SourceFiles: =?UTF-8?B?QzpcR1xhYmlsaXRlc3Qtc2VydmVyXFdlYlJvbGVcYXBpXHVzZXJcZXhpc3RzQnlOYW1l?=
X-Powered-By: ASP.NET
Date: Mon, 12 Jan 2015 17:52:12 GMT
Content-Length: 0
Then:
PUT http://localhost:3048/api/user/existsByName HTTP/1.1
Host: localhost:3048
Connection: keep-alive
Content-Length: 35
Accept: application/json, text/plain, */*
Origin: http://localhost:2757
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
Authorization: null
Content-Type: application/json;charset=UTF-8
Referer: http://localhost:2757/Auth/register
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
{"userName":"abdddcdefgg#live.com"}
giving:
HTTP/1.1 404 Not Found
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.0
Access-Control-Allow-Origin: http://localhost:2757
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: X-Custom-Header
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcR1xhYmlsaXRlc3Qtc2VydmVyXFdlYlJvbGVcYXBpXHVzZXJcZXhpc3RzQnlOYW1l?=
X-Powered-By: ASP.NET
Date: Mon, 12 Jan 2015 17:52:12 GMT
Content-Length: 0
The problem is even if the second request returns a 200 when I debug the success and error functions it still goes to the error function all of the time.
You should use JSONP to do cross domain JSON calls. Look at the documentation here: https://docs.angularjs.org/api/ng/service/$http#jsonp. Also, your referring page and the response from the OPTIONS request must have the appropriate CORS headers set or else the browser will refuse to send the request here are the header settings that I use.
Access-Control-Allow-Headers:Content-Type, Authorization, Content-Length, X-Requested-With, Accept, x-csrf-token, origin
Access-Control-Allow-Methods:GET,PUT,POST,DELETE,OPTIONS
Access-Control-Allow-Origin:*
To call $http.jsonp with a PUT request, you would set up a configuration such as
var config = {
method: 'POST',
data: { test: 'test' }
};
and then pass that into the $http.jsonp call
$http.jsonp('http://example.com', config);
Here is more documentation https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS and http://en.wikipedia.org/wiki/JSONP

Resources