How can I suppress the login dialogue caused by the WWW-Authenticate header? - http

When a user is unauthorised to access a page, I send a HTTP 401. Additionally, as required by the HTTP/1.1 spec, I also send a WWW-Authenticate header.
I know of at least 1 case where omitting this header causes an issue: Firebug (the Net tab will be empty).
A user can log in with both an email address or a username, and a password. The form is submitted over AJAX, and a JSON response takes care of redirecting the user after successfully logging in, or displaying an error message on failure.
On Windows Phone 8, a custom dialogue is shown when this header is present. It has fields for User name, Password, and Domain. It also has checkboxes for Show password and Remember my password.
The thing is, this dialogue doesn't work at all with the authentication process of the application.
The value of the header doesn't seem to matter, I've tried with WWW-Authenticate: form and WWW-Authenticate: blah but I get the dialogue regardless. How can I suppress this while still adhering to the spec?

From your question and the comments it seems you are doing form-based authentication, but, in order to comply with the HTTP spec, you thought you should return a 401, and, as that requires to also send the WWW-Authenticate header, you added that as well.
The fact of the matter is: Form-based authentication is non-standard, and you should not use 401 Unauthorized, which is to be used with standard HTTP authentication. So using a dummy authentication method might help you comply with the letter of the spec in terms of WWW-Authenticate, but you shouldn't be using 401 in the first place.
The spec reads:
10.4.2 401 Unauthorized
The request requires user authentication. The response MUST include a WWW-Authenticate header field containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field.
All this talk about HTTP headers (WWW-Authenticate and Authorization) makes it clear that this is about giving the client software the information needed to do the standard HTTP authentication (via a dialog in most cases).
Btw providing a custom authentication method in the WWW-Authenticate header makes sense when you want to to HTTP authentication, i.e. via the Authorization header, but use your own authentication scheme, rather than basic or digest. This of course requires a client that understands that custom scheme.
So what could you do instead? As form-authentication is non-standard, this is not defined in the specs, but how about redirecting the user to a/the page with the login form using a 307 Temporary Redirect, perhaps adding information so you can automatically redirect the user back to the page he wanted to access after verifying the credentials.

Related

How to add login credentials to URL

I tried https://myserver.com/~username=username&password=mypassword but it doesn't work.
Can you confirm that it's possible to pass the user/pass via HTTPs parameters (GET or POST)?
Basically, I want to access this link https://www.globalnorm.net/gn/doc.php?name=ASTM%20F%202638:2012-00&erx=0 (but I need to authenticate ) How can pass my username and password in URL?
The standard method to pass basic authentication to web servers is to use a url of the form:
http://user:password#domain.com/
Web servers do not expect basic authentication in the query parameters. You can, of course, implement your own authentication using query parameters / HTTP headers or any other method.
Update
The specific URL you had supplied redirects to https://www.globalnorm.net/login.php?ecd=S&info=nosessionorcookie&doc=....
The login path does not return the header WWW-Authenticate which is used to indicate that basic authentication is supported. So no point in trying HTTP basic authentication.
This specific login page seems to expect a POST request to /login.php with USR, PAS parameters. The answer will probably include a cookie which is later used to authenticate with the server.
There seems to be some controversy about whether or not browsers have dropped the feature, and/or whether the feature is deprecated. But unless your browser has in fact dropped the feature, then as noted in #nimrodm's answer above, you can specify a url with basic authentication as
http://user:password#domain.com/
However, you really should not use http protocol, since that will send the credentials in clear text. Instead, just use:
https://user:password#domain.com/
Note that you must urlencode special characters in the user or password fields (I frequently use '#' in my passwords, so those must be written as '%40').
The browser extracts the credentials, and passes them to the server in an Authorization header:
Authorization: Basic credentials
where the credentials are simply the (url-decoded) string "username:password" as written in the url, but base64-encoded. But since the https connection is encrypted, the header is encrypted and the credentials are not exposed outside the browser.
I think the whole issue about removing support or deprecating the feature was based on the security implications of specifying the credentials using http protocol. But with the availability of free ssl certificates, and the push for "ssl everywhere", that no longer seems like much of a problem these days.
Of course there's also the issue of how much good passing credentials this way does you. Many or most applications that require login expect to get the credentials from a form the user fills out and sends with a POST request. The application would have to be written to check each request for an Authorization header, and if present, process the credentials the same way they would if they had been specified by a POST of a filled-out login form.
Applications that expect HTTP basic authentication generally are built with that requirement built into the server configuration, e.g. using Apache directives along theses lines:
<Directory "/htdocs/protected">
AuthName "Registered User"
AuthType Basic
AuthUserFile /lib/protected.users
require valid-user
</Directory>
Where the file /lib/protected.users is a file of encrypted usernames and passwords generated by the Apache utility program htpasswd. With this configuration, any request for resources below /htdocs/protected is automatically checked by Apache for an Authentication header. If the request has no such header, or the credentials specified in the header do not match one of the pairs of usernames and passwords in /lib/protected.users, then the server responds with a 401 Unauthorized status and a header:
WWW-Authenticate Basic realm="Registered User"
Note that the realm value "Registered User" is the AuthName value from the Apache configuration. The browser handles this response by displaying a prompt requesting username and password, with the value of the realm contained in the prompt to give the user a hint as to what particular username and password is required.
Browsers have to treat the credentials specially anyway to convert them to an Authorization header, and so they also cache them and send them each time with requests to the same endpoint, like sending cookies. If they didn't do this, then the user would have to supply them on each subsequent url specifying that endpoint to avoid getting prompted.
Hope this helps.
The web server doesn't care about anything past the "?". This data gets sent to the application.
If you're actually authenticating to the application you would need to check the app's documentation for the correct parameter names.
In the past, you could supply the username:password#domain in the URL, but this has been disabled in many recent browsers because of security risks.
Currently, the only way I'm aware of to do an auto login is to set a basic auth header and do a form post, however you'll be better off to use a library that already knows how to do it, since the fields need to be encoded properly to work.
If I am correct in my assessment, the question is Can you confirm that it's possible to pass the user/pass via HTTPs parameters (GET or POST)?
Here is a snippet of code that I am using to send username and password as parameters to a GET call. Hope it helps.
$('#button').click(function () {
var username = $('#username').val();
var password = $('#password').val();
window.location.href = '#Url.Action("DesiredAction")?username=' + username + '&password=' + password;
});

What is the correct HTTP code to indicate "not logged in"?

If someone tries to visit an internal page which is only accessible once they have logged in, what error code should be returned? 403 doesn't seem right, because they have not authenticated. However, 401 doesn't work either, because that implies they can log in using basic auth, which we are not using.
Is it correct, when authentication is done via a method other than WWW-Authenticate headers, to use 403 in place of 401? If not, what code should be used?
Note: I have found some similar questions to this, but they all seem to be asking about sites using http basic auth, rather than any other authentication method.
The status code 401 does not imply you support basic authentication. It means that the server would not serve the request because appropriate credentials were missing.
The server can send back a WWW-Authenticate header to indicate what types of credentials it supports. If you only support JWT tokens for example, you would send back 'bearer'.

When is the Authorization header automatically sent by the browser?

I am trying to know when is the Authorization header sent automatically by the browser and when not.
By reading several posts and experimenting, I found out that the browser only sends the credentials:
When using Basic authentication, and only if the user input the username and password directly in the browser window (not, for example, if they were supplied in an XMLHttpRequest).
When using NTLM authentication
I would like to find a document which states when the browser should and should not send the header automatically (something like a specs document). I am especially interested in OAuth and Bearer Authorization header types.
Usually web browsers send Authorization header when it received 401 response. RFC 7235 "Hypertext Transfer Protocol (HTTP/1.1): Authentication
" says:
The "Authorization" header field allows a user agent to authenticate
itself with an origin server -- usually, but not necessarily, after
receiving a 401 (Unauthorized) response.
If you are finding specifications for HTTP authentication, see "Hypertext Transfer Protocol (HTTP) Authentication Scheme Registry" which provides the list of authentication schemes and the references.

Why does PayPal use HTTP Request Headers for its API authentication?

I'm just reading Paypal's API documentation, e.g. Adaptive Accounts API
My question: What's the reason/advantage of using (custom?) HTTP Request Headers for authentication instead of "normal" POST/GET (or even COOKIE) variables?
In the mentioned example PayPal uses the following HTTP Request Headers:
X-PAYPAL-SECURITY-USERID
X-PAYPAL-SECURITY-PASSWORD
X-PAYPAL-SECURITY-SIGNATURE
X-PAYPAL-APPLICATION-ID
X-PAYPAL-DEVICE-IPADDRESS
X-PAYPAL-REQUEST-DATA-FORMAT
Why use HTTP headers rather than something in the body of the request?
By keeping your authentication info separate from the payload (the data you are transmitting) you make it easier to handle authentication at an earlier stage in the request pipeline. For example, a gatekeeper server can receive requests and authenticate them by looking only at the headers, and then pass them along to the module/server/class that does parses the request body and does the real work.
If the request fails authentication, it can be rejected before it even gets near the code that deals with the money.
Of course, you can architect your system this way no matter what, but keeping it in the headers means you don't need to parse the request body or even look at it. You also don't need to worry about adjusting Content-Length: if you wanted to modify the headers before passing it along to another server.
Why use custom HTTP headers rather than WWW-Authenticate or Cookie?
I think this is simply because PayPal wants a more robust scheme than either of these can accommodate. WWW-Authenticate only allows for basic (cleartext) and digest (MD5) authentication, and many better schemes have been developed since the spec for these was written. They also don't allow for more than a username and password.
Cookies are technically opaque bits of data that you receive from a server and pass back to it unchanged. Again, they could tell you how to generate the info that you pass along in a Cookie header, but that wouldn't really be following the spec, so at that point, why not just use some custom headers?
The HTTP access authentication process is described in "HTTP Authentication: Basic and Digest Access Authentication", look here.
User agents are advised to take special care in parsing the WWW-Authenticate field value as it might contain more than one challenge, or if more than one WWW-Authenticate header field is provided, the contents of a challenge itself can contain a comma-separated list of authentication parameters.
If the connection is trusted between two parties and SSL is implemented, HTTP Authentication is a simple to implement way to authenticate between two fixed parties. The connection is simply rejected at the traffic level if the authentication fails.
I don't think Paypal uses HTTP Authentication for payments? It's just for you to access API features to build your own admin interface for Paypal accounts?

Why should I use HTTP basic authentication instead of username and password post parameters?

I have an API endpoint https://www.example.com/api/authentication which takes username and password as input and returns an authentication token.
In terms of passing username and password, I have two options (at least), namely:
HTTP Basic Authentication (which passes credentials as part of HTTP headers)
HTTP POST parameters
I understand that neither method provides encryption (hence the use of HTTPS/SSL). I also understand why using HTTP GET is is a Bad Idea.
Is there any real difference (aside from the fact that basic authentication feels more idiomatic) between the two methods?
The difference is that basic authentication is a well specified challenge/response scheme that all browsers understand and it is the server that starts it by telling a client that it requires (basic) authentication for a realm. This triggers the browser to show a popup to the user to enter a name/password which it then passes in the headers as you described.
In your second example you have to do all that in your own customized way and create your own login form for the user (etc).
If you deduct this process to the single step of passing the username/password from the client to the server I have to agree that there isn't that much difference but basic authentication implies a bit more than just that.
HTTP Basic authentication implementation is the simplest technique for enforcing access controls to web resources because it doesn't require cookies, session identifiers, or login pages; rather, HTTP Basic authentication uses standard fields in the HTTP header, obviating the need for handshakes.

Resources