HTTP authentication covers client-server authentication: the
process by which the web service client proves to the server that it has
some user’s credentials. What HTTP doesn’t cover is why the user should
trust the web service client with its credentials. This isn’t usually a
problem on the human web, because we implicitly trust our web browsers
(even when we shouldn’t, like when there’s spyware present on the
system). If I’m using a web application on
example.com, I’m comfortable supplying my
example.com username and
But what if, behind the scenes, the web application on
example.com is a client for eBay’s web
services? What if it asks me for my eBay authentication information so
it can make hidden web service requests to
ebay.com? Technically speaking, there’s no
difference between this application and a phishing site that pretends to
ebay.com, trying to trick me into
giving it my eBay username and password.
The standalone client programs presented in this book authenticate
by encoding the end user’s username and password in the
Authorization header. That’s how many web
services work. It works fine on the human web, because the HTTP clients
are our own trusted web browsers. But when the HTTP client is an
untrusted program, possibly running on a foreign computer, handing it
your username and password is naive at best. There’s another way. Some
web services attack phishing by preventing their clients from handling
usernames and passwords at all.
In this scenario, the end user uses her web browser (again,
trusted implicitly) to get an authorization token. She gives
this token to the web service client instead of giving her username and
password, and the web service client sends this token in the
Authorization header. The
end user is basically delegating the ability to make web service calls
as herself. If the web service client abuses that ability, its
authorization token can be revoked without making the user change her
Google, eBay, Yahoo!, and Flickr all have user-client authorization systems of this type. Amazon’s request signing, which I showed you in Chapter 3, fulfills the same function. There’s no official standard, but all four systems are similar in concept, so I’ll discuss them in general terms. When I need to show you specific URIs, I’ll use Google’s and Flickr’s user-client authorization systems as examples.
Let’s start with the simplest case: a web application that
needs to access a web service such as Google Calendar. It’s the simplest case because the web
application has the same user interface as the application that gives
out authorization tokens: a web browser. When a web application needs
to make a Google web service call, it serves an HTTP redirect that
sends the end user to a URI at
google.com. The URI might look something
https://www.google.com/accounts/AuthSubRequest ?scope=http%3A%2F%2Fwww.google.com%2Fcalendar%2Ffeeds%2F &next=http%3A%2F%2Fcalendar.example.com%2Fmy
That URI has two other URIs embedded in it as query variables.
scope variable, with a value of
http://www.google.com/calendar/feeds/, is the
base URI of the web service we’re trying to get an authorization token
next variable, value
will be used when Google hands control of the end user’s web browser
back to the web application.
When the end user’s browser hits this URI, Google serves a web
page that tells the end user that
example.com wants to access her Google
Calendar account on her behalf. If the user decides she trusts
example.com, she authenticates with
Google. She never gives her Google username or password to
After authenticating the user, Google hands control back to the
original web application by redirecting the end user’s browser to a
URI based on the value of the query variable
next in the original request. In this
next was http://calendar.example.com/my, so
Google might redirect the end user to http://calendar.example.com/my?token=IFM29SdTSpKL77INCn.
The new query variable
contains a one-time authorization token. The web application can put
this token in the
header when it makes a web service call to Google Calendar:
Authorization: AuthSub token="IFM29SdTSpKL77INCn"
Now the web application can make a web-service call as the end
user, without actually knowing anything about the end user. The
authentication information never leaves
google.com, and the authorization token is
only good for one request.
Those are the basics. Google’s user-client authorization
mechanism has lots of other features. A web service client can use the
one-time authorization token to get a “session token” that’s good for
more than one request. A client can digitally sign requests, similarly
to how I signed Amazon S3 requests back in Chapter 3. These features are different for every
user-client authorization mechanism, so I won’t dwell on them here.
The point is this flow (shown graphically in Figure 8-3): control moves from the
web application’s domain to the web service’s domain. The user
authenticates with the web service, and authorizes the foreign web
application to act on her behalf. Then control moves back to the web
application’s domain. Now the web app has an authorization token that
it can use in the
header. It can make web service calls without knowing the user’s
username and password.
For applications that expose a web interface, browser-based user-client authorization makes sense. The user is already in her web browser, and the application she’s using is running on a faraway server. She doesn’t trust the web application with her password, but she does trust her own web browser. But what if the web service client is a standalone application running on the user’s computer? What if it’s got a GUI or command-line interface, but it’s not a web browser?
There are two schools of thought on this. The first is that the end user should trust any client-side application as much as she trusts her web browser. Web applications run on an untrusted computer, but I control every web service client that runs on my computer. I can keep track of what the clients are doing and kill them if they get out of control.
If you as a service designer subscribe to this philosophy, there’s no need to hide the end user’s username and password from desktop clients. They’re all just as trustworthy as the web browser. Google takes this attitude. Its authentication mechanism for client-side applications is different from the web-based one I described above. Both systems are based on tokens, but desktop applications get an authorization token by gathering the user’s username and password and “logging in” as them—not by redirecting the user’s browser to a Google login page. This token serves little purpose from a security standpoint. The client needs a token to make web service requests, but it can only get one if it knows the user’s username and password—a far more valuable prize.
If you don’t like this, then you probably think the web browser is the only client an end user should trust with her username and password. This creates a problem for the programmer of a desktop client. Getting an authentication token means starting up a trusted client—the web browser—and getting the end user to visit a certain URI. For the Flickr service the URI might look like this:
The most important query variable here is
frob. That’s a predefined ID, obtained
through an earlier web service call, and I’ll use it in a moment. The
first thing the end user sees is that her browser suddenly pops up and
visits this URI, which shows a Flickr login screen. The end user gives
her authentication credentials and authorizes the client with
api_key=1234 to act on her behalf. In the
Google example above, the web service client was the web application
example.com. Here, the web
service client is the application running on the end user’s own
frob, the desktop
client at this point would have to cajole the end user to copy and
paste the authorization token from the browser into the desktop
client. But the client and the service agreed on a
frob ahead of time, and the desktop client
can use this
frob to get the
authorization token. The end user can close her browser at this point,
and the desktop client makes a GET request to a URI that looks like
The eBay and Flickr web services use a mechanism like this: what Flickr calls a frob, eBay calls an runame. The end user can authorize a standalone client to make web service requests on her behalf, without ever telling it her username or password. I’ve diagrammed the whole process in Figure 8-4.
Some mobile devices have network connectivity but no web browser. A web service that thinks the only trusted client is a web browser must make special allowances for such devices, or live with the fact that it’s locking them out.
Despite appearances, I’ve gone into very little detail: just enough to give you a feel for the two ways an end user might delegate her authority to make web service calls. Even in the high-level view it’s a complex system, and it’s worth asking what problem it actually solves. After all, the end user still has to type her username and password into a web form, and nothing prevents a malicious application writer from sending the browser to a fake authentication page instead of the real page. Phishers redirect people to fake sign-in pages all the time, and a lot of people fall for it. So what does this additional infrastructure really buy?
If you look at a bank or some other web site that’s a common
target of phishing attacks, you’ll see a big warning somewhere that
looks like this: “Never type in your
mybank.com username and password unless
you’re using a web browser and visiting a URI that starts with https://www.mybank.com/.” Common sense, right? It’s not
the most ironclad guarantee of security, but if you’re careful you’ll
be all right. Yet most web services can’t even provide this
milquetoast cover. The standalone applications presented throughout
this book take your service username and password as input. Can you
trust them? If the web site at
example.com wants to help you manage your
del.icio.us bookmarks, you need to give it your del.icio.us username
and password. Do you trust
The human web has a universal client: the web browser. It’s not a big leap of faith to trust a single client that runs on your computer. The programmable web has different clients for different purposes. Should the end user trust all those clients? The mechanisms I described in this section let the end user use her web browser—which she already trusts—as a way of bestowing lesser levels of trust on other clients. If a client abuses the trust, it can be blocked from making future web service requests. These strategies don’t eliminate phishing attacks, but they make it possible for a savvy end user to avoid them, and they allow service providers to issue warnings and disclaimers. Without these mechanisms, it’s technically impossible for the end user to tell the difference between a legitimate client and a phishing site. They both take your password: the only difference is what they do with it.