Since the web was in its infancy, HTTP has come with a built-in authentication protocol that was simple, if not particularly secure on the wire, supported by all browsers, and almost never used. Even with its security improved by digest authentication, pretty much every major website ignores HTTP Authentication in favour of a form-based approach that is in many ways worse. Why don't we like HTTP Authentication?
- Jarring User Interface
The login dialog, as implemented by web browsers, looks like part of the browser, not part of the site. The only explanatory text is what you can shoehorn into the realm-name, something that field was not intended to do. In addition, it's impossible to present the user with alternatives to logging in while they have the (at least page-modal) login dialog in front of them. You can not give them the option to sign up for a new account or request a password reminder beside the login form.
All this is just confusing and annoying to the user. Worse, it's ugly: a login form embedded in and styled with the site is orders of magnitude more aesthetically pleasing.
- Authentication Is Not Optional
Either a page requires authentication by returning a 401 response code, or it does not. Many websites, on the other hand, allow users to access pages whether they are logged in or not, controlling instead what content appears on those pages based on login status. Thus, HTTP Authentication is unsuitable.
- No Logout
It's really annoying and fiddly to code a logout option for HTTP Authentication, and you're never really sure the browser will take the hint. Configuring a time-out for idle users is just impossible.
- Poor Server Support
Historically, web– and web-application servers have dealt with HTTP Authentication badly: making it fiddly to configure, hard to plug in alternate providers, and hard to integrate with your applications.
On the other hand, there are certain things that are right about HTTP Authentication
- Browser Support
The browser understands, at the protocol level, how to determine if a page requires authentication, and which credentials to send. Modern browsers give users the option to remember credentials, and seamlessly remain logged into the site between sessions.
The alternative, as we've all probably had dealings with, involves messing around with user sessions, and putting the user at risk with authentication tokens buried in cross-site-scripting-vulnerable persistent cookies.
Just as annoyingly, there's the idle timeout problem. We sometimes want to time idle user logins out (for their own safety), but we really have no idea whether the user is idle or not. We've all had that nasty experience of spending a little too long filling out a form, only to lose everything we entered when we find out we've been logged out when it came time to submit it.
- Simplicity
It is far, far easier to build a tool that can perform HTTP Auth, than it is to build one that can navigate the myriad login forms that clutter the web. For example, consider a password-protected RSS feed. It would be easy to write an RSS Newsreader that could retrieve it if HTTP Auth were used, much harder if anything else were put in its place.
My solution is pretty straightforward. Back-port current practice (optional login and in-page login forms) into the standards. First, provide for optional authentication in HTTP:
WWW-Authenticate
The server MAY include a WWW-Authenticate header (as defined in RFC2617) with any successfully retrieved (2xx response code) document. This header denotes that the document was retrieved, but further information may be available if the user authenticates to the realm provided in the header.
On receiving a WWW-Authenticate header with a 2xx response, any user-agent that has credentials cached for the realm SHOULD repeat the request, including those credentials. If the user-agent has no credentials cached for the given realm, it SHOULD NOT interrupt the delivery of the response to the user, but MAY provide some indication that the page accepts authentication, and some mechanism to enter credentials.
As in RFC2617, the user-agent MAY preemptively send the same credentials for any resource located at a URI beneath the one at which the WWW-Authenticate header was received.
Then, provide for HTTP Auth from within web pages.
When a
FORM
element has amethod
attribute value of "Auth", this defines a form for providing HTTP Authentication credentials. Itsaction
attribute value is taken to be the name of an HTTP Authentication realm as defined in RFC2617. Authentication forms may contain the following form input elements:
username
, which will be the username for the login credentials.password
, which will be the password for the login credentials.timeout
, which will be an optional idle-timeout (in minutes) for the credentials provided in this form.The exact definition of idleness is left to the user-agent, but is roughly defined as the amount of time since the user last interacted with a page that required authentication to that particular realm. If timeout is zero, or this field is not provided, the login is assumed to never time out.
On submitting an "Auth" form, the user-agent should cache the credentials for the given realm. If the page on which the form was located was part of that realm and new credentials have been provided, the page should be re-requested with the new credentials. If the page on which the form was located was not part of that realm, it MUST NOT be requested with those credentials, for obvious reasons.
An "Auth" form may also have an optional
input
element of typelogout
. User-agents should render this element in the same manner as inputs of typecancel
. Selecting this element will cause the user-agent to forget all authentication tokens for the given realm.
Voila. Now all we need is server and tool support, and we're on our way back to a better web.
Update: Zoe points out that the authentication form has appeared before in a 1999 W3C Draft. Which just goes to show that few good ideas are ever original. Shame it was never implemented though.