Avoid HTTP auth popup in a chrome extension (digest) - javascript

I'm currently developing a chrome extension, I need to access some http-auth protected resources (webdav). The HTTP auth is using (in the best case) a digest authentication.
I'm able to do the auth directly in the ajax request using the https://login:password#domain.tld/path/to/ressource form.
The issue is : if the login/password is wrong, I can't just get a 401 status (unauthorized), Chrome pops up the regular authentication dialog. Which I don't want cause it's confusing for user and I can't save the credentials from here.
EDIT: Another use-case I faced is : I want to check if a resource is password-protected without trying to provide credentials to actualy access it.
Any ideas on how to catch the 401 without poping the Chrome's auth box ?

Google Chrome teams has implented the onAuthRequired event in Google Chrome 22, so now is possible detect when the HTTP Basic Authentication is required.
In fact I wrote a extension that automatically sends the HTTP Basic Authentication credentials using the onAuthRequired event.
It is available for free in the official Google Chrome web store:
https://chrome.google.com/webstore/detail/basic-authentication-auto/dgpgkkfheijbcgjklcbnokoleebmeokn
Usage example of onAuthRequired event:
sendCredentials = function(status)
{
console.log(status);
return {username: "foo", password: "bar"};
}
chrome.webRequest.onAuthRequired.addListener(sendCredentials, {urls: ["<all_urls>"]}, ["blocking"]);
You need to add the right permissions to the manifest file in order to use the onAuthRequired.
"permissions": [ "http://*/*", "https://*/*", "webRequest", "webRequestBlocking", "tabs" ],
Download the extensions and check the source code for a better approach.
It should work even if the request was initiated from another extension.

It's really seems to be a lack in chrome behavior, other people are wishing to see something as the mozBakgroundRequest Chris highlighted, there already a a bug report for that.
There are (hackish) workarounds suggested by some developers in the bugtracker :
use a webworker and a timeout to perform the request
do the same with the background page
In both case, the benefit is that it won't pop an authentication box... But you will never know if it's a real server timeout or a 401. (I didn't tested those workarounds).

I think this is impossible. If you are using the browser's http client then it will prompt the user for credentials on a 401.
EDIT : Over in mozilla land https://developer.mozilla.org/en/XMLHttpRequest check out "mozBackgroundRequest".

Related

Chrome extension get authorization token from header

I'm working on an extension that will make request to Robinhood API and get all transaction history to generate a better report.
Initial thought, it will be easier to just grab auth token from chrome extension(background.js) and use that to make request to Robinhood API but seems like it's more complicated than I expected.
I can still see the authorization token on the Chrome browser console but can't find the way to grab that from my Chrome extension(pic below)
Thought webRequest API is the answer but found it won't provide Authorization info(https://developer.chrome.com/docs/extensions/reference/webRequest/)
chrome.webRequest.onBeforeSendHeaders.addListener((details) => {
console.log(details);
},
{ urls: ["<all_urls>"] },
["requestHeaders", "extraHeaders"]
);
I know there's Chrome extensions making http requests to Robinhood API with local auth token. What's the best way to grab that local auth token?
Thank you all!
Thank you to #wOxxOm for the answer!
I was missing host_permissions in manifest.json.
The Authorization token info shows up after adding that.

Chrome Extension Not Sending Request [duplicate]

I've written a Chrome Extension for my library. It makes an AJAX call to api.library.edu (school's library).
My extension uses jQuery and my code looks like this:
$.get("http://api.library.edu/?period=1month", function (data) {
// process data
});
When I load my Extension, it makes the AJAX call and I get data back.
Right now I give absolutely no permissions to my extension (permissions is []).
Is my extension going to work when I publish it? Shouldn't it require special permissions to make AJAX calls with jQuery?
Thanks! I'm just making sure I wrote my extension correctly.
Your extension does not need any additional permissions to make AJAX calls from within the same origin. However, if api.library.edu does not set the proper CORS headers, you may need to request cross-origin permission for that domain:
{
"name": "My extension",
...
"permissions": [
"http://api.library.edu/"
],
...
}
From Google's Docs:
Each running extension exists within its own separate security origin. Without requesting additional privileges, the extension can use XMLHttpRequest to get resources within its installation.
...
By adding hosts or host match patterns (or both) to the permissions section of the manifest file, the extension can request access to remote servers outside of its origin.
If your extension is already working though, that would lead me to believe that the library API already has cross-domain headers set, and that you will not need any additional permissions.

Embedded credentials alternatives for HTTP requests

A while ago I created a chrome extension called MalOnTheGo. It has been working well however chrome is now dropping support for the way I access resources from an API. The Chromestatus for the drop can be found here. They are dropping support for a format of urls called Embedded Credentials. I have looked for alternatives however I haven't been able to find anything.
In the API documentation they specify formatting the link in the same way I do using jQuery with the username and password parameters like this :
"Usage Examples:
CURL:
curl -u user:passwordhttps://myanimelist.net/api/account/verify_credentials.xml
This is one of the code snippets that chrome is alerting me will not work at some point in June.
function verifyCredentials(username, password, error, success) {
$.ajax({
"url": "https://myanimelist.net/api/account/verify_credentials.xml",
"error": error,
"username": encodeURIComponent(username),
"password": encodeURIComponent(password),
"success": success
});
}
The API's documentation states that this is the way to access that resource.
Is there anything I can change on my end or is this the only way I can use it and the API developers need to update their implementation?
Any alternatives to what I currently have would help
Thanks
You may find CORS to be helpful for making a cross-domain request to verify credentials. There is a lot of helpful info in this tutorial:
https://www.html5rocks.com/en/tutorials/cors/
You can still use ajax to make your request, you will just need to add some more headers for authentication. There is a section specifically for Chrome extensions as well:
https://www.html5rocks.com/en/tutorials/cors/#toc-cross-domain-from-chrome-extensions

What permissions (if any) I need to give my Chrome Extension to let it make remote AJAX calls?

I've written a Chrome Extension for my library. It makes an AJAX call to api.library.edu (school's library).
My extension uses jQuery and my code looks like this:
$.get("http://api.library.edu/?period=1month", function (data) {
// process data
});
When I load my Extension, it makes the AJAX call and I get data back.
Right now I give absolutely no permissions to my extension (permissions is []).
Is my extension going to work when I publish it? Shouldn't it require special permissions to make AJAX calls with jQuery?
Thanks! I'm just making sure I wrote my extension correctly.
Your extension does not need any additional permissions to make AJAX calls from within the same origin. However, if api.library.edu does not set the proper CORS headers, you may need to request cross-origin permission for that domain:
{
"name": "My extension",
...
"permissions": [
"http://api.library.edu/"
],
...
}
From Google's Docs:
Each running extension exists within its own separate security origin. Without requesting additional privileges, the extension can use XMLHttpRequest to get resources within its installation.
...
By adding hosts or host match patterns (or both) to the permissions section of the manifest file, the extension can request access to remote servers outside of its origin.
If your extension is already working though, that would lead me to believe that the library API already has cross-domain headers set, and that you will not need any additional permissions.

How can I suppress the browser's authentication dialog?

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.

Categories