If you are designing a REST api, you should adhere to REST principles. There are two important ones to highlight for authentication:
- Identification of resources through URIs
- State transitions through server-supplied links.
To adhere to principle 1, you need to keep your authentication out of your URI.
http://example.org/list-of-stuff?auth-token=12345 is not a different resource from
http://example.org/list-of-stuff?auth-token=67890, so it should not have a different URI. Having different URIs also makes it impossible to cache the resource across different users.
In general, if the resource would be different depending on some condition, that condition needs to be in the URI. For example, many websites have a
/profile url, but what profile you see depends on the invisible "who is logged in" state. This is not RESTful. Instead the url should contain the user, e.g.
/profiles/username. Whether you actually get to see that resource depends on whether you are authorized to see it, which depends on whether you are authenticated as a user that is authorized. Authentication is a separate layer from resource identification. (For example, suppose you have an admin user which can see other people's profiles. If you have just a
/profile url, how would you architect a method for him to see other profiles? Clearly the presence of a resource is something different from the ability to see it and from who is looking at it.)
So we have established that authentication should not be via parameters in the URI. Since we are using HTTP, we can either provide it in a header, or provide it outside HTTP itself.
Although it's not very common, some REST apis handle authentication at the SSL layer using client certificates. This is great from a technical standpoint, but the user experience is baffling and terrible. Although this article is from 2008, nothing has improved. This approach is also not easily scriptable from browser JS, and even outside the browser it's cumbersome to write an application that has to provide client certificates. Development on the server side is difficult, too, because most web scripting environments do not give you easy access to SSL-layer stuff at all, let alone more esoteric SSL features like client-certificates. Your application may not be able to know what certificate identity was provided with the request.
So that leaves HTTP in the header. We can either use a traditional cookie-based auth, where we "log in" at a special url and get a token back, or HTTP authentication which is natively supported by HTTP.
The downside is that the only HTTP auth methods that are in common use and well supported are Basic and Digest, and both of them are not very secure. They're probably fine if you only use https, but otherwise they are terrible.
Also HTTP auth is useless for normal browser use by humans: no custom login pages, no way to present "forgot password" functionality or other authentication customizations, and still browser makers have provided no easy way to "log out" (i.e., forget the credentials for the current realm)!
Cookie-based auth provides you the most control, but you need to keep server- and client-side authentication state and worry about a whole host of other security issues, such as session fixation or even what constitutes a session! Is it IP address, user agent, some combination? How long should an authenticated session be valid before we expire it? What if there's a proxy involved and the IP address changes frequently? What should we do when the magic token expires? What should we do when the user is not authorized? (You can't use an HTTP 401 response--you need to define your own method specific to your site.) In essence, you need to define your own complex session and authentication protocol or adopt someone else's. At least with HTTP auth, the only thing you need to worry about is an attacker reading your Authenticate headers, and using SSL solves that problem.