I am making an ajax request using Jquery and everything works fine except the page is protected so only logged in users can make request. I am already logged in but I think Jquery ajax doesn't send my cookies to the url. How can I solve this error so cookies, headers are also sent so the page doesn't treat it as 401 request?
Thanks in advance :)
It sounds like you're trying to request a page on a different domain from the one your site is running on. If this is the case then it's the browser that is telling you the request is unauthorized rather than the other site.
Edit:
If this is the case and you control the other website then I believe you can allow requests using a specific header (http://www.w3.org/TR/2008/WD-access-control-20080912/#access-control-allow-origin). If you don't control the other server then there is no (pure javascript) way round this problem.
You could run a proxy on a server you control to request the page and pass it on to you. However this will still have the problem that it will be requesting the page without your user's cookies.
my jquery solution:
in your ajax call(for basic authorization):
headers: {
"Authorization": "Basic " + btoa('username:password')
},
or
beforeSend: function (xhr){
xhr.setRequestHeader('Authorization', "Basic " + btoa('username:password'));
},
You still can check session as normal
Related
I am working on express js and a particular endpoint renders the page using
res.render('dialog',{state:'admin'});
This endpoint is at http://localhost:3000/api/login. When i open this link in the browser, it opens the dialog.ejs page but when i call this endpoint using a GET request from another part of the server, the dialog.ejs page is not rendered
request({
url: 'http://localhost:3000/api/login',
headers:{
'Authorization' : auth
},
method: 'GET'
}, function(err, response, body) {
console.log("Response to request for authorization code : " + response.statusCode);
});
Please help !
Well, when you build a handmade request chances are that you're missing half of the headers the browser is sending, so that can be one of the reasons the whole thing is failing
On the other, if your making a machine to machine request, you DON'T want the ejs page renders, You only need to recover the neeeded data and /or make the server do something "as you were login in from a browser".
And as you're including the authorization Header, you're probably trying to simulate a login or authorization of some kind ( maybe a JWT Token ?)
Any case i think oyour only options is to mimic what your browser do as far as possible . So Build a perfectly correct set of headers, inject what will
be the result of form data, probably url_encoded, and use the correct request method (GET is perfectly correct, but coming from an html from POST is much more common. check it)
Just only one suggestion. Rendering a full web page from an /api/login seems a bit incorrect. Usually Api enpoints talk JSON only. In and out
I'm using basic authentication to secure a set of WCF web services exposed only inside our corporate network, and I was wondering if there was a way to trigger the browser's credentials dialog to appear from an AJAX call when the web service returns with a 401 error?
Currently my AJAX call receives the 401 as a regular failed request and doesn't prompt the browser to do anything. However, if I take the same URI and copy-paste it into into the browser's URL bar, the returned 401 correctly triggers the Basic Authentication dialog.
Is there any way to get the AJAX callback to tell the browser to pop up that dialog?
Dynamically create an iframe with your url and append to document. It'll trigger authentication form. jQuery snipet to add iframe
$('<iframe src="your_url"></iframe>').appendTo('body')
A very simplified example is here:
var url = 'your_url_here';
$.ajax({
url: url,
error: function(response){
if(response.status==401){
$('<iframe src="'+url+'"></iframe>').appendTo('body');
}
},
success:function(){
//your success code here
}
});
I have faced almost the same 401 problem, except for my request was cross domain. But I hope the reason is the same. Following the instructions on developer.mozilla - Access control CORS I have finally succeeded with simple:
var xhttp=new XMLHttpRequest();
xhttp.withCredentials = true;
xhttp.open("GET", "https://my.foo.server/app/resource", true);
xhttp.send();
I think the xhttp.withCredentials is the solution. It is not header! You let browser to communicate with server through cookies. The following answer explains a lot XHR2 withCredentials - which cookies are sent?
Without xhttp.withCredentials there was always 401 (Unauthorized). But using it, the browser added the required header Authorization:Basic dGVFooFooFooFoosaWVudA== or triggered the login dialog, when credentials were not available yet.
You can't, you'll need to provide the request with the credentials.
See How to use Basic Auth with jQuery and AJAX?
You would suggest to open/display/insert a form to allow inserting username and password and than resend the AJAX Request with the given credentials. I wouldn't really on browsers credential popup.
How you set authentication header you can read here: How to use Basic Auth with jQuery and AJAX?
Yes, you can invoke it from AJAX. Just pass the request with the following header:
withCredentials: true
As found somewhere in the stack :
Receiving a 401 response is the server telling you, “you aren’t
authenticated–either not authenticated at all or authenticated
incorrectly–but please reauthenticate and try again.” To help you out,
it will always include a WWW-Authenticate header that describes how to
authenticate
Use jQuery's beforeSend callback to add an HTTP header with the authentication information
beforeSend: function (xhr) {
xhr.setRequestHeader ("Authorization", "Basic " + btoa(username + ":" + password));
},
Do you meet the conditions highlighted in this SO answer?
Also based on in this other answer you may want to check that the headers returned from your backend are the same whether you request it from the browser or from an AJAX call.
you could just trigger a redirect when you check for the 401 condition:
window.location = "https://example.com"
I am building a static website with restricted access. I have configured the server to protect a subfolder (say www.example.com/restricted) with HTTP Basic Auth.
Now, I do not want to use the standard browser popup for the login, since it's ugly and does not remember the password across sessions. And it's ugly, did I mention that? =)
So, I am showing a html form, and try to do the authentication via JavaScript (here, with help of jQuery, but the "raw" version showed the same behaviour). The function I am calling looks like
try_login = function(username, password){
$.ajax({
url: '/restricted/login.token',
method: 'GET',
beforeSend: function(request) {
request.setRequestHeader(
'Authorization',
'Basic ' + Base64.encode(username + ':' + password));
},
success: function () { window.location='/restricted/'; },
error: function () { $('#error_message').text("Wrong password."); }});
}
Now, the authentication works for the ajax request. "login.token" is served correctly with status code 200 if I use the correct username and password, and I get a 401 if I don't.
But the browser (I tested Chrome 28 and IE 10) asks again for the credentials following the redirect in the success callback. It does not seem to save the credentials.
Am I doing something wrong, or is this indeed the expected behaviour? If it is, is there a way to cheat? I really think the browser popup is ugly.
Since this is a static site, any authentication scheme required active server-side code is unfortunately not usable here.
You need to send the Authorization header with each request.
Try this approach - How to use Basic Auth with jQuery and AJAX?
I am trying to make a cross-site request, on a site that needs authentication. The authentication works with a cookie.
For some reason, when I am doing this call :
$.getJSON(url + '?', function(data){
alert(data);
});
I don't see the Cookie sent in the HTTP headers. While when I just copy paste url in my address bar, the call is successful, and Cookie is set properly...
I tried to replace the $.getJSON by a $.ajax, and set manually the request headers. It resulted in the request not even visible in firebug (while I know it has been sent and answered to by using another tool)!!!
I am using firefox 3.6, jquery 1.4
Any idea on what's going on ?
This is part of the same origin policy, JSONP requests to other domains will not have any cookies sent with them.
I swear I saw an article about this at one point but can not find it...
How can I perform a jQuery ajax request of type POST on another domain? Must be accomplished without a proxy. Is this possible?
Yes you can POST all you want, even $.post() works...but you won't get a response back.
This works, the other domain will get the POST:
$.post("http://othersite.com/somePage.php", { thing: "value" }, function(data) {
//data will always be null
});
But the response, data in the above example, will be null due to the same-origin policy.
All the options I've experimented with:
1) PORK: http://www.schizofreend.nl/Pork.Iframe/Examples/ Creates an iframe and submits the post there, then reads the response. Still requires same base domain per
request (i.e. www.foo.com can request
data from www2.foo.com, but not from
www.google.com) . Also requires you to
fiddle with the document.domain
property, which causes adverse side
effects. And there's a pervasive problem in all the major browsers where reloading the page basically shuffles the cached contents of all iframes on the page if any of them are dynamically written. Your response data will show up in the box where an ad is supposed to be.
2) flxhr: http://flxhr.flensed.com/ Can even be used to mask jQuery's built-in ajax so you don't even notice it. Requires flash though, so iPhone is out
3) jsonp: Doesn't work if you're posting a lot of data. boo.
4) chunked jsonp: When your jsonp request is too big, break the query string up into manageable chunks and send multiple get requests. Reconstruct them on the server. This is helpful but breaks down if you're load balancing users between servers.
5) CORS: http://www.w3.org/TR/cors/ doesn't work in older browsers (IE7, IE6, Firefox 2, etc)
So we currently do the following algorithm:
If request is small enough, use JSONP
If not small enough, but user has flash, use FlXHR
Else use chunked JSONP
Spend one afternoon writing that up and you'll be able to use it for good. Adding CORS to our algorithm might be good for faster iPhone support.
If you have control over the code running at the other domain, just let it return an appropriate Access-Control-Allow-Origin header in the response. See also HTTP Access-Control at MDC.
If you want a fire and forget POST where you don't care about the response then just submit a form to a hidden iframe. This requires a Transitional Doctype.
<form method="POST" action="http://example.com/" target="name_of_iframe">
If you want to parse the response, then using a proxy if the only real option.
If you are desperate, and control the remote site, then you can:
Submit a form as above
Set a cookie in the response (which might be blocked before the iframe could cause the cookie to be considered '3rd party' (i.e. likely to be advertising tracking).
Wait long enough for the response to come back
Dynamically generate a script element with the src pointing to the remote site
Use JSON-P in the response and take advantage of the data previously stored in the cookie
This approach is subject to race conditions and generally ugly. Proxing the data through the current domain is a much better approach.
If you need to know that the POST was successful, and don't have control over the remote server:
$.ajax({
type:"POST",
url:"http://www.somesite.com/submit",
data:'firstname=test&lastname=person&email=test#test.com',
complete: function(response){
if(response.status == 0 && response.statusText == "success")
{
/* CORS POST was successful */
}
else
{
/* Show error message */
}
}
});
If there was a problem with the submission then response.statusText should equal "error".
Note: some remote servers will send the HTTP header Access-Control-Allow-Origin: *, which will result in a 200 OK HTTP status code response. In that case, ajax will execute the success handler, and this method is not needed. To look at the response just do console.log(JSON.stringify(response)); or use FireBug's 'Net' panel.