XMLHttpRequest response access denied despite same-origin - javascript

response is JSON
Edge: sometimes inserts response property value into DOM briefly then removes it, sometimes logs error "SCRIPT5: access denied" (indicating CORS), response fully accessible from Debugger, request shown in network tab
Chrome: response empty string, request not shown in network tab, no console message
Firefox: console error 'response "malformed JSON"' on breakpoint line using response in JSON.parse(), thus before usage, request not shown in network tab, Firebug and integrated
JS (current browsers only):
var session = "";
var request;
function checkLogin()
{
if(request.readyState > 3)
{
var response = JSON.parse(request.response);
if(verify(response)) // verify inserts argument property "error" in DOM on error via innerHTML on element
{
// do something
}
}
}
function login()
{
request = new XMLHttpRequest();
request.onreadystatechange = checkLogin;
request.open("GET", "authenticateUser.php?user=" + document.getElementById("user").value + "&credential="+md5(document.getElementById("password").value));
request.send();
}
Edge request from network tab:
Anforderungs-URL: http://*MYDOMAIN*/authenticateUser.php?user=df&credential=d41d8cd98f00b204e9800998ecf8427e
Anforderungsmethode: GET
Statuscode: 200 / OK
- Anforderungsheader
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: de-DE, de; q=0.8, en-US; q=0.5, en; q=0.3
Connection: Keep-Alive
Host: *MYDOMAIN*
Referer: http://*MYDOMAIN*/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586
- Antwortheader
Connection: Keep-Alive
Content-Length: 65
Content-Type: application/json
Date: Sat, 21 Nov 2015 07:42:17 GMT
Keep-Alive: timeout=15, max=94
Server: Apache
X-Powered-By: PHP/5.5.29
response:
{"success":false,"error":"authentication failed or unauthorised"}
What is going to make my phps' response be usable in JS code (in Chrome and Firefox) and its properties value be insertable into the DOM?

login() is the handler of onsubmit. I didn't return false; thus the form from which the user and pw came from - having no action - submitted to its own page and made the browser reload the page: cancelling the request in Chrome and Ff. Only Edge let the equal page JS handle the repsonse from the former loads request - until it was to be inserted.
Took me 6 hours and a detour through JSONP and Charles then listing the network traffic from Chrome where the page itself appeared after the request thus letting me have the idea that the page "reloaded" and finally remembering onsubmits handler cancels the submit with return false and else submits leading to a load of the action (or self if none) which is what happened here.

Related

xmlhttprequest not posting to php file

I hope this is not a duplicate...
I am trying to POST user email & password to a php file and it seems that the php file isn't getting those values.
The js code:
function ReceiveLoginData() {
let text = this.responseText;
console.log(text);
let json_data = JSON.parse(
text.substring(1, text.length - 1).replaceAll("\\u0022", "\"")
);
// there is a lot more code... but its irrelevant.
}
function SubmitLogin() {
var email_addr = document.getElementsByClassName("login-email")[0].value;
var passwd = document.getElementsByClassName("login-passwd")[0].value;
var req = new XMLHttpRequest();
req.onload = ReceiveLoginData;
// req.onreadystatechange = ReceiveLoginData; // does not work...
req.open("POST", "/users/auth/login.php"); // ...,true); or ...,false); fail too...
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
let data_to_send = "uemail=" +
window.encodeURIComponent(email_addr) +
"&upasswd=" +
window.encodeURIComponent(passwd);
// data_to_send = "uemail="+email_addr ... works neither
req.send(data_to_send);
}
PHP (actually its location is localhost:4000/users/auth/login.php)
<?php
$uemail = $_POST["uemail"];
$upasswd = $_POST["upasswd"];
$login_err = true;
// set it to false otherwise
function SendData(string $str)
{
echo json_encode($str, JSON_HEX_QUOT | JSON_HEX_APOS);
}
function main_fn()
{
$uemail = strtolower($uemail);
if (strlen($uemail) == 0) {
SendData("[\"noemail\"]");
}
// and much more but again irrelevant...
}
main_fn();
?>
I learnt that using window.encodeURIComponent(...) is safer from here: https://stackoverflow.com/a/17382629/18243229
but neither of the ways work.
Whatever I got to know after literal 5 hours of debugging and getting fed up(I blame my noviceness):
The PHP form is being executed. ReceiveLoginData function prints ["noemail"] whenever the submit button is pressed
The Network debugging tab in chrome's dev tools shows that connection is established with php file.
Some information which might just be useful:
Response Headers (source):
HTTP/1.1 200 OK
Host: localhost:4000
Date: Sun, 18 Sep 2022 16:59:49 GMT
Connection: close
X-Powered-By: PHP/8.1.10
Content-type: text/html; charset=UTF-8
Request Headers (source):
POST /users/auth/login.php HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 31
Content-type: application/x-www-form-urlencoded
Host: localhost:4000
Origin: http://localhost:4000
Referer: http://localhost:4000/users/auth/auth.html?
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Linux"
Payload: (source | URL encoded)
uemail=email%40gmail.com&upasswd=1234
uemail: email%40gmail.com
upasswd: 1234
Response:
"[\u0022noemail\u0022]"
What else I did...
I didn't waste those 5 hours on this project...
I tried to remake a smaller project with the same mechanism and the same js code calling a PHP file and voila, the php file got the values posted to it...
Everything "seems" correct according to my knowledge but why does PHP not get the $_POST values?
Also, I'm currently focusing on Google Chrome and am on Linux (ig that makes no difference...)
From the code you have posted i can spot one problem.
the $uemail = $_POST["uemail"]; is in the global scope and the code inside the main_fn function is trying to use that variable but that variable is not available in that scope because it is only available in the global scope. So it seems to me you need to pass them as arguments to get them into the functions scope.
Changeing the function definition
from: function main_fn()
to: function main_fn($uemail, $upasswd)
and calling it
with: main_fn($uemail, $upasswd);
instead of: main_fn();
should do the trick
Hope this helps :-)

'400 - Bad Request' when sending GET request with Node.js/got library

I'm making an api that communicates with a website to pull player statistics. I've made multiple POST/GET HTTP/1 requests to the server to get a session token and player ID. I then use those values(valid values which I have tested before passing to my function) in my last function to fetch player statistics. The last request is a HTTP/2 GET request. I'm using the got library and vanilla Node. Here is my request:
//THESE ALL HAVE SOME VALUE AFTER I USE SOME OF MY FUNCTIONS; THE FUNCTION I'M
//HAVING TROUBLE WITH IS THE LAST FUNCTION AND IS PASSED VERIFIED NON-NULL VALUES
var session = {
app_id: '3587dcbb-7f81-457c-9781-0e3f29f6f56a',
space_id: '5172a557-50b5-4665-b7db-e3f2e8c5041d',
session_id: null,
ticket: null,
};
var player = {
name: null,
id: null,
platform: 'uplay',
kills: null,
deaths: null,
rank: null,
};
async function get_player_stats(session, player) {
var platform = 'PC';
if (player.platform === 'uplay') {
platform = 'PC';
}
var options = {
':authority': 'r6s-stats.ubisoft.com',
':method': 'GET',
':path': `/v1/current/operators/${player.id}?gameMode=all,ranked,casual,unranked&platform=${platform}&teamRole=attacker,defender&startDate=20200723&endDate=20201120`,
':scheme': 'https',
'authorization': `ubi_v1 t=${session.ticket}`,
'ubi-appid': session.app_id,
'ubi-sessionid': session.session_id,
'content-type': 'application/json',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36',
}
const url = `https://r6s-stats.ubisoft.com/v1/current/operators/${player.id}?gameMode=all,ranked,casual,unranked&platform=${platform}&teamRole=attacker,defender&startDate=20200723&endDate=20201120`;
try {
const response = got(url, {headers: options, http2: true});
console.log(response);
}
catch (err) {
console.log(err);
}
}
//FUNCTION CALL
async function fetch(user) {
var stats_string = await get_player_stats(session, player);
console.log(stats_string);
}
fetch(username);
Chrome's request header from network log:
:authority: r6s-stats.ubisoft.com
:method: GET
:path: /v1/current/operators/e96ae749-8939-43ed-895f-bf1817e849d9?gameMode=all,ranked,casual,unranked&platform=PC&teamRole=attacker,defender&startDate=20200723&endDate=20201120
:scheme: https
accept: */
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
authorization: ubi_v1 t= LONG TOKEN
dnt: 1
expiration: 2020-11-21T09:13:54.804Z
origin: https://www.ubisoft.com
referer: https://www.ubisoft.com/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
ubi-appid: 3587dcbb-7f81-457c-9781-0e3f29f6f56a
ubi-sessionid: d78f3306-0e5c-4ac8-ad63-5a711b816f76
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36
Chrome's Response header from network tools:
access-control-allow-credentials: true
access-control-allow-origin: https://www.ubisoft.com
content-encoding: gzip
content-length: 16969
content-type: application/json
date: Sat, 21 Nov 2020 06:14:47 GMT
status: 200
vary: Origin
What I've tried:
I've tried just about everything. I've googled what causes 400 errors, which apparently are mostly user error, and I've looked through my code for days and also looked at Chrome's network activity. I've tried matching Chrome's request header with mine to no avail(my header variable is one of many iterations I've tried--pretty sure I've tried every combination of possible headers). However, sometimes I'll get 400 bad error, or an invalid header response from the server. I've tried using the vanilla Node http2Client.request and that gives me an invalid header/400 as well.
Okay, finally figured out why this wasn't working. I missed one tiny line in what I thought I already tried millions of times.
In the request header on the Chrome Network activity there is a field for expiration.
I needed to set the expiration value in the header to get the data.
So the value I needed to add to my header in my code was:
expiration: 2020-11-21T09:13:54.804Z
Future edit: The expiration is the date in ISO format. You can make a date Object and convert to ISO:
var time = new Date();
var expiration = time.toISOString();
function someRequest() {
var options = {
'expiration': expiration,
}
}

jquery $.ajax call results in 401 unauthorized response when in Chrome or Firefox, but works in IE

I have a script running on a web page that needs to use the JQuery $.ajax method (currently using jquery 1.7.2) to submit several GET requests to a service endpoint on a different domain. I have the ajax call working in IE (9, 10, 11), but it fails with a 401 Unauthorized response in Firefox and Chrome. Part of the additional error message in Chrome is "Full authentication is required to access this resource".
My ajax call is setup like this (dataType is "json" for these requests that fail, and async is true):
$.ajax({
url: url,
type: "GET",
async: isAsync,
dataType: dataType,
username: user,
password: pswd,
success: function (response, status) {
// success code here
},
failure: function (response, status) {
// failure code here
},
complete: function (xhr, status) {
// on complete code here
}
});
I am passing in the username and password required to access the service and this works in IE. I was understanding that the JQuery ajax function would handle the authentication correctly, so if a response comes back indicating that authorization is required, it would use the credentials that were provided to make that request correctly. Am I missing something here? Do I need to manually add the Authorization header for this to work?
UPDATE:
Here is the request, response, and cookie info reported by Chrome and IE via the F12 debugging tools (some info replaced with [...removed...])
Chrome (42.0.2311.90 m)
Response Headers
access-control-allow-credentials:true
access-control-allow-origin:[...removed...]
access-control-expose-headers:
cache-control:private,max-age=0,must-revalidate connection:keep-alive
content-encoding:gzip content-length:296
content-type:text/html;charset=ISO-8859-1 date:Tue, 21 Apr 2015
20:55:12 GMT expires:Tue, 21 Apr 2015 20:55:12 GMT p3p:CP="NON DSP COR
CURa PSAa PSDa OUR NOR BUS PUR COM NAV STA"
set-cookie:JSESSIONID=qd-app-1348vf1vrksvc76oshcwirvjp.qd-app-13;Path=/;Secure;HttpOnly
set-cookie:NSC_vt1.sbmmzefw.dpn!-!IUUQT=ffffffff09091c3945525d5f4f58455e445a4a42378b;path=/;secure;httponly
status:401 Unauthorized vary:Accept-Encoding version:HTTP/1.1
www-authenticate:Basic realm="Rally ALM"
Request Headers
:host:rally1.rallydev.com :method:GET :path:[...removed...]
:scheme:https :version:HTTP/1.1 accept:application/json,
text/javascript, /; q=0.01 accept-encoding:gzip, deflate, sdch
accept-language:en-US,en;q=0.8 origin:[...removed...]
referer:[...removed...] user-agent:Mozilla/5.0 (Windows NT 6.1; WOW64)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90
Safari/537.36
Response Cookies
JSESSIONID qd-app-1348vf1vrksvc76oshcwirvjp.qd-app-13
NSC_vt1.sbmmzefw.dpn!-!IUUQT
ffffffff09091c3945525d5f4f58455e445a4a42378b
IE 11
Request Headers
Request GET [...removed...] Referer [...removed...] Accept
application/json, text/javascript, /; q=0.01 Accept-Language en-US
Accept-Encoding gzip, deflate User-Agent Mozilla/5.0 (Windows NT
6.1; WOW64; Trident/7.0; rv:11.0) like Gecko Host [...removed...] Connection Keep-Alive Cache-Control no-cache Cookie
JSESSIONID=qd-app-08xmftgye78tde1b0wzcl2kit4m.qd-app-08;
NSC_vt1.sbmmzefw.dpn!-!IUUQT=ffffffff09091c3145525d5f4f58455e445a4a42378b;
RALLY-Detail-treeCollapsed=false;
ZSESSIONID=RpKo5acfRqmjPhW0vIU1rgurWmDhlka0lrGCY9MIWhU;
SUBBUCKETID=713
Response Headers
Response HTTP/1.1 200 OK RallyRequestID
qd-app-08xmftgye78tde1b0wzcl2kit4m.qd-app-0810353108 Expires Thu, 01
Jan 1970 00:00:00 GMT Content-Type text/javascript; charset=utf-8
ETag "0101c2c8d3463ee3c1a4f950d4142b7d3" P3P CP="NON DSP COR CURa
PSAa PSDa OUR NOR BUS PUR COM NAV STA" Cache-Control
private,max-age=0,must-revalidate Date Tue, 21 Apr 2015 20:58:17 GMT
Connection keep-alive Set-Cookie
ZSESSIONID=RpKo5acfRqmjPhW0vIU1rgurWmDhlka0lrGCY9MIWhU;Path=/;Domain=[...removed...];Secure;HttpOnly
Set-Cookie
SUBBUCKETID=713;Path=/;Domain=[...removed...];Secure;HttpOnly
Content-Length 319
Cookies
Sent JSESSIONID qd-app-08xmftgye78tde1b0wzcl2kit4m.qd-app-08
Sent NSC_vt1.sbmmzefw.dpn!-!IUUQT
ffffffff09091c3145525d5f4f58455e445a4a42378b Sent
RALLY-Detail-treeCollapsed false Sent ZSESSIONID
RpKo5acfRqmjPhW0vIU1rgurWmDhlka0lrGCY9MIWhU Sent
SUBBUCKETID 713 Received ZSESSIONID
RpKo5acfRqmjPhW0vIU1rgurWmDhlka0lrGCY9MIWhU At end of session
[...removed...] / Yes Yes Received SUBBUCKETID 713 At end of
session [...removed...] / Yes Yes
I came across a jquery forum post that had some additional information regarding this issue. Based on what I found there, I added this to the $.ajax call:
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', makeBaseAuth(user, pswd));
}
where makeBaseAuth() uses the btoa() function like this:
makeBaseAuth: function(user, pswd){
var token = user + ':' + pswd;
var hash = "";
if (btoa) {
hash = btoa(token);
}
return "Basic " + hash;
}
That appears to be working in Chrome now, I'm not getting a login prompt or a 401 response, the request is going through and I get the expected response. I also removed the option xhrFields: { withCredentials: true } as that didn't appear to be necessary. For some reason this isn't working in Firefox yet, and in the Firefox debugger I can't actually get at the javascript to do any decent debugging to see what the problem is, the way this script works is its loaded into a web page as an anonymous script and I don't have any control over that. I have a way to get at the script in IE and Chrome, but not Firefox for some reason. I'll consider this a win just getting it to work in Chrome, thanks to everyone for prodding me in the right direction!

Issue adding access token to header in Backbone: It changes the method

I am using backbone to get data from an API. This all works fine when there is no authorization required and when I add the authorization to the API, I get the expected 401 - unauthorised response.
[from the console log:
GET http://localhost:999/api/tasks 401 (Unauthorized)
]
I've then add in this code to add the bearer authorization to the header for every call:
var backboneSync = Backbone.sync;
Backbone.sync = function (method, model, options) {
/*
* The jQuery `ajax` method includes a 'headers' option
* which lets you set any headers you like
*/
var theUser = JSON.parse(localStorage.getItem("happuser"));
if (theUser !== null)
{
var new_options = _.extend({
beforeSend: function(xhr) {
var token = 'Bearer' + theUser.authtoken;
console.log('token', token);
if (token) xhr.setRequestHeader('Authorization', token);
}
}, options)
}
/*
* Call the stored original Backbone.sync method with
* extra headers argument added
*/
backboneSync(method, model, new_options);
};
Once I include this code, the API sends the request with a method of OPTIONS instead of GET and I obviously get a 405 invalid method response.
Here is the console log output
OPTIONS http://localhost:999/api/tasks 405 (Method Not Allowed) jquery-1.7.2.min.js:4
OPTIONS http://localhost:999/api/tasks Invalid HTTP status code 405
Any idea why the send method would be changing?
ADDITIONAL DISCOVERY:
It appears when I do a model.save it does the same thing., even if I don't actually change the model.
FURTHER DETAILS: This is the Request/Response for the call without authorisation...
Request URL:http://localhost:999/api/tasks
Request Method:GET
Status Code:200 OK
Request Headersview source
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6
Host:localhost:999
Origin:http://localhost
Proxy-Connection:keep-alive
Referer:http://localhost/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36
Response Headersview source
Access-Control-Allow-Headers:*
Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin:http://localhost
Cache-Control:no-cache
Content-Length:3265
Content-Type:application/json; charset=utf-8
Date:Wed, 13 Nov 2013 14:51:32 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
As soon as I add the sync override code in the response changes to this:
Request URL:http://localhost:999/api/tasks
Request Method:OPTIONS
Status Code:405 Method Not Allowed
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6
Access-Control-Request-Headers:accept, authorization
Access-Control-Request-Method:GET
Host:localhost:999
Origin:http://localhost
Proxy-Connection:keep-alive
Referer:http://localhost/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36
Response Headersview source
Access-Control-Allow-Headers:*
Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Origin:http://localhost
Allow:GET,POST
Cache-Control:no-cache
Content-Length:76
Content-Type:application/json; charset=utf-8
Date:Wed, 13 Nov 2013 14:56:52 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
It would appear you are issuing a "not so simple request ™":
you're making a CORS request
and you're setting a custom header
In that case, your browser divides your request in two : a preflight request (the OPTIONS verb you see) and the actual request once the permissions have been retrieved.
To quote the article linked:
The preflight request is made as an HTTP OPTIONS request (so be sure
your server is able to respond to this method). It also contains a few
additional headers:
Access-Control-Request-Method - The HTTP method of the actual request.
This request header is always included, even if the HTTP method is a
simple HTTP method as defined earlier (GET, POST, HEAD).
Access-Control-Request-Headers - A comma-delimited list of non-simple
headers that are included in the request.
The preflight request is a way of asking permissions for the actual
request, before making the actual request. The server should inspect
the two headers above to verify that both the HTTP method and the
requested headers are valid and accepted.

XmlHttpRequest CORS POST sent without cookies

I have a Rails service returning data for my AngularJS frontend application. The service is configured to allow CORS requests by returning the adequate headers.
When I make a GET request to receive data, the CORS headers are sent, as well as the session cookie that I have previously received on login, you can see for yourself:
Request URL:http://10.211.194.121:3000/valoradores
Request Method:GET
Status Code:200 OK
Request Headers
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Cookie:_gestisol_session=BAh7B0kiDHVzZXJfaWQGOgZFRmkASSIPc2Vzc2lvbl9pZAY7AEZJIiVmYTg3YTIxMjcxZWMxNjZiMjBmYWZiODM1ODQzMjZkYQY7AFQ%3D--df348feea08d39cbc9c817e49770e17e8f10b375
Host:10.211.194.121:3000
Origin:http://10.211.194.121:8999
Pragma:no-cache
Referer:http://10.211.194.121:8999/
User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36
X-Requested-With:XMLHttpRequest
Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin
Access-Control-Allow-Methods:GET,POST,OPTIONS
Access-Control-Allow-Origin:http://10.211.194.121:8999
Access-Control-Max-Age:1728000
Cache-Control:max-age=0, private, must-revalidate
Connection:Keep-Alive
Content-Length:5389
Content-Type:application/json; charset=utf-8
Date:Mon, 04 Nov 2013 14:30:51 GMT
Etag:"2470d69bf6db243fbb337a5fb3543bb8"
Server:WEBrick/1.3.1 (Ruby/1.9.3/2011-10-30)
X-Request-Id:15027b3d323ad0adef7e06103e5aa3a7
X-Runtime:0.017379
X-Ua-Compatible:IE=Edge
Everything is right and I get my data back.
But when I make a POST request, neither the CORS headers nor the session cookie are sent along the request, and the POST is cancelled at the server as it has no session identifier. These are the headers of the request:
Request URL:http://10.211.194.121:3000/valoraciones
Request Headers
Accept:application/json, text/plain, */*
Cache-Control:no-cache
Content-Type:application/json;charset=UTF-8
Origin:http://10.211.194.121:8999
Pragma:no-cache
Referer:http://10.211.194.121:8999/
User-Agent:Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36
X-Requested-With:XMLHttpRequest
Request Payload
{valoracione:{revisiones_id:1, valoradores_id:1}}
valoracione: {revisiones_id:1, valoradores_id:1}
And the service answers with a 403 because the request does not contain the session cookie.
I don't know why the POST request fails, as the $resource is configured just like the other one and I have defined the default for $httpProvider to send the credentials (and it works right as the GET request succeeds):
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}])
This is the failing resource when I call $save() on an instance:
'use strict';
angular.module('gestisolApp')
.service('ValoracionesService', ['$resource', 'API_BASE_URL', function ValoracionesService($resource, API_BASE_URL) {
this.valoraciones = $resource(API_BASE_URL + '/valoraciones');
}]);
And this is the service that succeeds with the query() call:
'use strict';
angular.module('gestisolApp')
.service('ValoradoresService', ['$resource', 'API_BASE_URL', function ValoradoresService($resource, API_BASE_URL) {
this.valoradores = $resource(API_BASE_URL + '/valoradores');
}]);
They are much like the same.
Does anybody know why the POST is sent without the session cookie?
Edit
Just to complete the information, preflight is handled by the following method, and is handled OK as the request before the failing POST is an OPTIONS that succeeds with a 200 response code:
def cors_preflight_check
headers['Access-Control-Allow-Origin'] = 'http://10.211.194.121:8999'
headers['Access-Control-Allow-Methods'] = 'GET,POST,OPTIONS'
headers['Access-Control-Allow-Headers'] = 'X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin'
headers['Access-Control-Allow-Credentials'] = 'true'
headers['Access-Control-Max-Age'] = '1728000'
render :nothing => true, :status => 200, :content_type => 'text/html'
end
This is the CORS OPTIONS request/response exchange previous to the failing POST:
Request URL:http://10.211.194.121:3000/valoraciones
Request Method:OPTIONS
Status Code:200 OK
Request Headers
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, x-requested-with, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:10.211.194.121:3000
Origin:http://10.211.194.121:8999
Referer:http://10.211.194.121:8999/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.101 Safari/537.36
Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin
Access-Control-Allow-Methods:GET,POST,OPTIONS
Access-Control-Allow-Origin:http://10.211.194.121:8999
Access-Control-Max-Age:1728000
Cache-Control:max-age=0, private, must-revalidate
Connection:Keep-Alive
Content-Length:1
Content-Type:text/html; charset=utf-8
Date:Mon, 04 Nov 2013 15:57:38 GMT
Etag:"7215ee9c7d9dc229d2921a40e899ec5f"
Server:WEBrick/1.3.1 (Ruby/1.9.3/2011-10-30)
X-Request-Id:6aa5bb4359d54ab5bfd169e530720fa9
X-Runtime:0.003851
X-Ua-Compatible:IE=Edge
Edit 2: I have changed the title to reflect clearly my problem
I had a similar problem and adding the following before angular $http CORS request solved the problem.
$http.defaults.withCredentials = true;
Refer https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS#Requests_with_credentials for more details.
When CORS is involved, then your browser will send an OPTIONS request before the POST request.
I don't know the specifics with Rails, but I guess you have to configure Rails to actually answer the OPTIONS request with the adequate CORS headers.
The following code is just for comparison - it shows how you would address the issue in Java:
public void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("Access-Control-Allow-Origin", "http://10.211.194.121:8999");
resp.setHeader("Access-Control-Allow-Credentials", "true");
resp.setHeader("Access-Control-Allow-Methods", "OPTIONS, POST, GET");
resp.setHeader("Access-Control-Allow-Headers", "X-Requested-With,X-Prototype-Version,Content-Type,Cache-Control,Pragma,Origin");
resp.setHeader("Access-Control-Max-Age", "600");
resp.setHeader("Access-Control-Expose-Headers","Access-Control-Allow-Origin");
super.doOptions(req, resp);
}
But it might get you on the right track how to configure it in Rails.
Ok, finally I figured out what was happening.
By the answer posted on this question, I removed the HttpOnly parameter from the cookie and got it working on Firefox. Later for Chrome was just a matter of applying the rest of recommendations from the answer to make it work, like setting a domain for the cookie.

Categories