I am attempting to use XMLHTTPRequest to get an update on twitter.
var XMLReq = new XMLHttpRequest();
XMLReq.open("GET", "http://twitter.com/account/verify_credentials.json", false, "TestAct", "password");
XMLReq.send(null);
However, using my sniffer I cannot see any authorization headers being passed through. Hence, I get a 401 error response from Twitter.
The account and password are correctly entered.
Anyone attempt this? Can anyone give me some pointers? Thank you.
You just need to add a Authorization header, a user name and password in a base64 encoded string as follows.
XMLReq.setRequestHeader("Authorization", "Basic " + btoa("username:password"));
In cross-origin requests, you have to explicitly set the withCredentials flag if you want user credentials to be sent.
See http://www.w3.org/TR/XMLHttpRequest/#the-withcredentials-attribute (where user credentials includes HTTP authentication)
Due to the Origin policy, you cannot make a XMLHttpRequest from your domain to another domain. E.g. you cannot use http://twitter.com/... URLs unless your script was loaded from twitter.com. If your script is loaded from http://localhost/, the AJAX request also need to go to localhost.
Related
I am trying to access Adyen test API that requires basic authentication credentials. https://docs.adyen.com/developers/ecommerce-integration
My credentials work when accessing the API page through browser.
But I get an 401 Unauthorized response when trying to access the API with XMLHttpRequest POST request.
Javascript Code
var url = "https://pal-test.adyen.com/pal/servlet/Payment/v25/authorise";
var username = "ws#Company.CompanyName";
var password = "J}5fJ6+?e6&lh/Zb0>r5y2W5t";
var base64Credentials = btoa(username+":"+password);
var xhttp = new XMLHttpRequest();
xhttp.open("POST", url, true);
xhttp.setRequestHeader("content-type", "application/json");
xhttp.setRequestHeader("Authorization", "Basic " + base64Credentials);
var requestParams = XXXXXXXX;
xhttp.send(requestParams);
Result
That screenshot shows “Request Method: OPTIONS”, which indicates the details displayed are for a CORS preflight OPTIONS request automatically made by your browser—not for your POST.
Your browser doesn’t (and can’t) send the Authorization header when it makes that OPTIONS request, and that causes the preflight to fail, so the browser never moves on to trying your POST.
As long as https://pal-test.adyen.com/pal/servlet/Payment/v25/authorise requires authentication for OPTIONS requests, there’s no way you can make a successful POST to it.
The reason is because what’s happening here is this:
Your code tells your browser it wants to send a request with the Authorization header.
Your browser says, OK, requests with the Authorization header require me to do a CORS preflight OPTIONS to make sure the server allows requests with that header.
Your browser sends the OPTIONS request to the server without the Authorization header—because the whole purpose of the OPTIONS check is to see if it’s OK to send that.
That server sees the OPTIONS request but instead of responding to it in a way that indicates it allows Authorization in requests, it rejects it with a 401 since it lacks that header.
Your browser expects a 200 or 204 response for the CORS preflight but instead gets that 401 response. So your browser stops right there and never tries the POST request from your code.
The PAL is a Payment Authorisation API. You never want to call it from a browser. You only want to expose your username and password to send in payments in your backend code.
In Client-side encryption, the encryption is done in the browser. You then send the encrypted data to your own server. On your server you then create a payment authorization request (of which the encrypted data is one of the elements, along side payment amount, etc).
If you would be able to manage to make this run from your browser, your end solution will allow your shoppers to change amounts, currency's, payment meta data etc from the JavaScript layer. This should never be the case.
The authorization is for that reason part of the "Server side" integration part of documentation: https://docs.adyen.com/developers/ecommerce-integration?ecommerce=ecommerce-integration#serverside
Depending on your server side landscape the CURL implementation in your favorite language differs, but most of the time are easy to find.
Kind regards,
Arnoud
I'm attempting to create an HTML-file that acts as a direct link to a cached site made by proxysite. Is there any way I can send a form containing a URL, without having the user fill in any field?
Sending it via ajax like so:
var params = {
"d" : "http://www.web.site/"
};
$.ajax({
url: "https://eu1.proxysite.com/includes/process.php?action=update",
type: "POST",
data: params
});
Seems to be purposefully blocked, as it returns this error message:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
EDIT: I realize why the above won't work. Since I don't have access to the previously mentioned website, I am looking for a possible workaround.
The reason you are receiving the "No Access-Control-Allow-Origin" header is because the receiving server needs to provide CORS headers. If you have access to the proxysite you will need to set the following headers to allow your request to go through
<?php
header("Access-Control-Allow-Origin: *");
Where the asterisk is the domain you want to allow. If you leave the asterisk in the the server will accept all requests from any local scripts on any domain.
Regarding sending the form without having the user input any fields-- Yes, it's possible to send data without user input. The way you are doing it is the correct way to send data via the jQuery Ajax method.
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 currently in the process of implementing a server-side OAuth2 flow in order to authorize my application.
The JS application will be displaying YouTube Analytics data on behalf of a registered CMS account to an end user (who own's a channel partnered with the CMS account). As a result of this, the authorization stage needs to be completely hidden from the user. I am attempting to authorize once, then use the 'permanent' authorization code to retrieve access tokens as and when they're needed.
I am able to successfully authorize, and retrieve an access code. The problem begins when i attempt to exchange the access code for a token.
The HTTP POST Request to achieve this needs to look like this...
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=8819981768.apps.googleusercontent.com&
client_secret={client_secret}&
redirect_uri=https://oauth2-login-demo.appspot.com/code&
grant_type=authorization_code
I am using this code to achieve this:
var myPOSTRequest = new XMLHttpRequest();
myPOSTRequest.open('POST', 'https://accounts.google.com/o/oauth2/token', true);
myPOSTRequest.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
myPOSTRequest.send('code=' + myAuthCode + '&redirect_uri=http%3A%2F%2Flocalhost%2FCMSAuth3.html&client_id=626544306690-kn5m3vu0dcgb17au6m6pmr4giluf1cle.apps.googleusercontent.com&scope=&client_secret={my_client_secret}&grant_type=authorization_code');
I can successfully get a 200 OK response to this Request however no access token is returned, and myPOSTRequest.responseText returns an empty string.
I have played with Google's OAuth Playground - and can successfully get a token using my own credentials.
Am i missing something here?
You cannot do this, because there is the same origin policy. This is a security concept of modern browsers, which prevents javascript to get responses from another origin, than your site. This is an important concept, because it gives you the ability, to protect you against CSRF. So don't use the code authorization flow, use instead the token authorization flow.
Try and build up the full URL. Then dump it in a webbrowser. If its corect you will get the json back. You have the corect format.
https://accounts.google.com/o/oauth2/token?code=<myAuthCode>&redirect_uri=<FromGoogleAPIS>&client_id=<clientID>&client_secret={my_client_secret}&grant_type=authorization_code
Other things to check:
Make sure that you are using the same redirect_uri that is set up in google apis.
How are you getting the Authcode back? If you are riping it from the title of the page i have had issues with it not returning the full authcode in the title try checking the body of the page. This doesnt happen all the time. I just ocationally.
My web application has a login page that submits authentication credentials via an AJAX call. If the user enters the correct username and password, everything is fine, but if not, the following happens:
The web server determines that although the request included a well-formed Authorization header, the credentials in the header do not successfully authenticate.
The web server returns a 401 status code and includes one or more WWW-Authenticate headers listing the supported authentication types.
The browser detects that the response to my call on the XMLHttpRequest object is a 401 and the response includes WWW-Authenticate headers. It then pops up an authentication dialog asking, again, for the username and password.
This is all fine up until step 3. I don't want the dialog to pop up, I want want to handle the 401 response in my AJAX callback function. (For example, by displaying an error message on the login page.) I want the user to re-enter their username and password, of course, but I want them to see my friendly, reassuring login form, not the browser's ugly, default authentication dialog.
Incidentally, I have no control over the server, so having it return a custom status code (i.e., something other than a 401) is not an option.
Is there any way I can suppress the authentication dialog? In particular, can I suppress the Authentication Required dialog in Firefox 2 or later? Is there any way to suppress the Connect to [host] dialog in IE 6 and later?
Edit
Additional information from the author (Sept. 18):
I should add that the real problem with the browser's authentication dialog popping up is that it give insufficient information to the user.
The user has just entered a username and password via the form on the login page, he believes he has typed them both correctly, and he has clicked the submit button or hit enter. His expectation is that he will be taken to the next page or perhaps told that he has entered his information incorrectly and should try again. However, he is instead presented with an unexpected dialog box.
The dialog makes no acknowledgment of the fact he just did enter a username and password. It does not clearly state that there was a problem and that he should try again. Instead, the dialog box presents the user with cryptic information like "The site says: '[realm]'." Where [realm] is a short realm name that only a programmer could love.
Web broswer designers take note: no one would ask how to suppress the authentication dialog if the dialog itself were simply more user-friendly. The entire reason that I am doing a login form is that our product management team rightly considers the browsers' authentication dialogs to be awful.
I encountered the same issue here, and the backend engineer at my company implemented a behavior that is apparently considered a good practice : when a call to a URL returns a 401, if the client has set the header X-Requested-With: XMLHttpRequest, the server drops the www-authenticate header in its response.
The side effect is that the default authentication popup does not appear.
Make sure that your API call has the X-Requested-With header set to XMLHttpRequest. If so there is nothing to do except changing the server behavior according to this good practice...
The browser pops up a login prompt when both of the following conditions are met:
HTTP status is 401
WWW-Authenticate header is present in the response
If you can control the HTTP response, then you can remove the WWW-Authenticate header from the response, and the browser won't popup the login dialog.
If you can't control the response, you can setup a proxy to filter out the WWW-Authenticate header from the response.
As far as I know (feel free to correct me if I'm wrong), there is no way to prevent the login prompt once the browser receives the WWW-Authenticate header.
I don't think this is possible -- if you use the browser's HTTP client implementation, it will always pop up that dialog. Two hacks come to mind:
Maybe Flash handles this differently (I haven't tried yet), so having a flash movie make the request might help.
You can set up a 'proxie' for the service that you're accessing on your own server, and have it modify the authentication headers a bit, so that the browser doesn't recognise them.
I realize that this question and its answers are very old. But, I ended up here. Perhaps others will as well.
If you have access to the code for the web service that is returning the 401. Simply change the service to return a 403 (Forbidden) in this situation instead 401. The browser will not prompt for credentials in response to a 403. 403 is the correct code for an authenticated user that is not authorized for a specific resource. Which seems to be the situation of the OP.
From the IETF document on 403:
A server that receives valid credentials that are not adequate to
gain access ought to respond with the 403 (Forbidden) status code
In Mozilla you can achieve it with the following script when you create the XMLHttpRequest object:
xmlHttp=new XMLHttpRequest();
xmlHttp.mozBackgroundRequest = true;
xmlHttp.open("GET",URL,true,USERNAME,PASSWORD);
xmlHttp.send(null);
The 2nd line prevents the dialog box....
What server technology do you use and is there a particular product you use for authentication?
Since the browser is only doing its job, I believe you have to change things on the server side to not return a 401 status code. This could be done using custom authentication forms that simply return the form again when the authentication fails.
In Mozilla land, setting the mozBackgroundRequest parameter of XMLHttpRequest (docs) to true suppresses those dialogs and causes the requests to simply fail. However, I don't know how good cross-browser support is (including whether the the quality of the error info on those failed requests is very good across browsers.)
jan.vdbergh has the truth, if you can change the 401 on server side for another status code, the browser won't catch and paint the pop-up.
Another solution could be change the WWW-Authenticate header for another custom header. I dont't believe why the different browser can't support it, in a few versions of Firefox we can do the xhr request with mozBackgroundRequest, but in the other browsers?? here, there is an interesting link with this issue in Chromium.
I have this same issue with MVC 5 and VPN where whenever we are outside the DMZ using the VPN, we find ourselves having to answer this browser message. Using .net I simply handle the routing of the error using
<customErrors defaultRedirect="~/Error" >
<error statusCode="401" redirect="~/Index"/>
</customErrors>
thus far it has worked because the Index action under the home controller validates the user. The view in this action, if logon is unsuccessful, has login controls that I use to log the user in using using LDAP query passed into Directory Services:
DirectoryEntry entry = new DirectoryEntry("LDAP://OurDomain");
DirectorySearcher Dsearch = new DirectorySearcher(entry);
Dsearch.Filter = "(SAMAccountName=" + UserID + ")";
Dsearch.PropertiesToLoad.Add("cn");
While this has worked fine thus far, and I must let you know that I am still testing it and the above code has had no reason to run so it's subject to removal... testing currently includes trying to discover a case where the second set of code is of any more use. Again, this is a work in progress, but since it could be of some assistance or jog your brain for some ideas, I decided to add it now... I will update it with the final results once all testing is done.
I'm using Node, Express & Passport and was struggling with the same issue. I got it to work by explicitly setting the www-authenticate header to an empty string. In my case, it looked like this:
(err, req, res, next) => {
if (err) {
res._headers['www-authenticate'] = ''
return res.json(err)
}
}
I hope that helps someone!
I recently encountered the similar situation while developing a web app for Samsung Tizen Smart TV. It was required to scan the complete local network but few IP addresses were returning "401 Unauthorized" response with "www-authenticate" header attached. It was popping up a browser authentication pop requiring user to enter "Username" & "Password" because of "Basic" authentication type (https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication).
To get rid from this, the simple thing which worked for me is setting credentials: 'omit' for Fetc Api Call (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). Official documentation says that:
To instead ensure browsers don’t include credentials in the request, use credentials: 'omit'
fetch('https://example.com', {
credentials: 'omit'
})
For those unsing C# here's ActionAttribute that returns 400 instead of 401, and 'swallows' Basic auth dialog.
public class NoBasicAuthDialogAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
base.HandleUnauthorizedRequest(filterContext);
filterContext.Result = new HttpStatusCodeResult(400);
}
}
use like following:
[NoBasicAuthDialogAuthorize(Roles = "A-Team")]
public ActionResult CarType()
{
// your code goes here
}
Hope this saves you some time.