14.3. How do I handle authentication in REST?

QUESTION: Most services require user to login before exploring further. If cookies are not recommended in REST, does it mean I have to go thru authentication on every single request (e.g., HTTP AUTH)?

ANSWER: There are two basic approaches here. The first is, use HTTP AUTH. The (human) user will be prompted for the credential just once (or they will be loaded from file, depending on the system at hand). The client software will compute the Base64 encoding of the credentials and will include them in each future HTTP request to the server (using the "Authorization" HTTP header).

The second alternative is to create a dedicated login service, that accepts credentials and returns a token. This token should then be included, as a URL argument, to each following request (e.g., by addding "&authtoken=XYZ" to the URL). Of course, the API (including the argument's name) should be clearly defined.

Each approach has its benefits, and its limitations. The first approach is easy to test using browsers. Just connect to the service with your browser, and on the first visit, you'll get a the username/password prompt. The browser than caches your credentials and automatically sends them on all following requests (just like the REST client software would have done!). The main advantage of the second approach is that tokens can be created with an expiration date (managed on the server, unlike cookie expiration). For some services, this is important.

And what about cookies? As I said elsewhere, these violate the "state transfer" notion of REST, where the complete state should be passed with each request. While cookies can be limited to function just like the Authorization header, why do that when you have a dedicated, special-purpose header?

16 comments:

SRIRAM said...

Hi I understood the concept. If I want to pass any sensitive data (ex: credit card information) through browser, how to authenticate that URI? can you provide me small example to understood easily.

LKRaider said...

@SRIRAM You should always use SSL/TLS to encrypt the connection as it will all be easily intercepted otherwise.

Also, I would use a public/private key on the application level and encrypt all POST data on the client using the server public key before sending it.

TechnicalPhilosopher said...

Dr Elkstein
If we are indeed using GET, wouldn't having a server token to the user be a security hazard of sorts (I am assuming here that it has to be included in all the url requests after), should we use POST when we are using the token architecture?
Also wouldn't a static token be a security hazard of sorts in itself, especially if we are using GET?
Sorry if I sound like nub, though I am fairly new to this

Dr. M. Elkstein said...

Hello TechnicalPhilosopher,

There is no added security in using POST over GET, unless your main worry is people peeking over the user's shoulder. As for using tokens, the token can be bound, for example, to a specific IP, and created with an expiration time. This makes tokens more secure, in fact, than simple resends of the username and password (even if hashed, as in the case of the Authentication HTTP header).

Håvard Pedersen said...

Passing an authkey in the url is basically the same as using normal sessions, since the server has to verify the authkey serverside.

Paul DeMarco said...

Isn't your second approach just the same as a cookie approach?
"here client, keep this data for later"
Either as a variable in the code or cookie on disk...

I have to ask, why not cookies?

Dr. M. Elkstein said...

Hi Paul,

The main difference is that the cookie is not passed in the URL, as opposed to the token I've mentioned. Other than that, you're obviously right, and the mechanism can be implemented using cookies; but cookies tend to be abused, with too much state stored there. The solution I'm suggesting explicitly limits the state to log-in status.

Julien Montenoise said...

Hello,

As Paul DeMarco said, it's equivalent to store the token in a cookie or to send it in the URL. In both cases, your client application have to keep the token somewhere...
The drawback to add it in the url is that you must force to add it for every queries whereas it's automatic with the cookie!
Moreover, the url is "polluted" by the token that is completely technical.

When we say that REST is stateless, it's of course on the service side and not on the client side...

Gunawan Wibisono said...

Hi,

I agree with Paul DeMarco and Julien Montenoise. While cookies can be manipulated, parameters in URL is even more so.

I always thought the "Stateless" rule means on the server side (no sessions), not on the client side (no cookies). Because no matter how the client side keeps the token, whether in a cookie or variable, it's still some kind of (client-side) state.

Dr. M. Elkstein said...

Hi Julien, Gunawan,

This really depends on your application: if it's browser-based, then cookies are indeed easier and make more sense. But if you have HLL code generating the requests, adding tokens to the URL makes it easier to generate the request and to log things; there's nothing "automatic" about cookies if you generate the HTTP request in code, rather than using a browser.

José Manuel López Muñoz said...

Hi DR. M. ELKSTEIN,
We are developing a REST api and we have doubts about send a GET like this
https://server/api/login.json?email=test@test.com&password=test

This is clearly wrong, I know... but unless do it like a POST over SSL and encrypt the password (maybe this is the way we must do it), we don't know any other way to make the login.

We are a litte lost about how to do it right, can you please give us some information or an example to do this?

Regards,
Jose M.

gilly3 said...

If the server is managing token expiration, then the server is no longer stateless. It is unrealistic to re-authenticate a user with each request, so this aspect of maintaining state must be the exception for a RESTful service that requires authentication.

It is inaccurate to imply that storing data in a cookie means that the data is not sent with each request. With HTTP, the entire cookie is sent to the server with each request. Whether the auth token is included in an authentication header, the url, the post data, or the cookie, it is all included in every HTTP request. Use of cookies is an implementation detail and would not violate the stateless constraint of REST.

Why use a cookie when you have a dedicated, special-purpose header? Because a cookie can be persisted beyond a single browser session. A user on a private computer, who choses to allow the browser to store auth tokens in a persistent cookie (ie, opts to "remember me"), should not be required to re-authenticate for each browser session.

Unknown said...

Hi Gilly,
the server is still stateless. Once created, the token encodes its own state (ip address, expiry date, etc). The server is only validating the token when a request is sent.

As discussed earlier, you're right, there is no functional difference between tokens and cookies. Only as Elkstein points out, cookies are effectively browser only and so don't lend themselves to use in more general API calls from other programs or scripts. See eg twitter, facebook, and other web services that provide programmable APIs. And of course, both can be supported in a service depending on the type of client.

Qa Engg said...

Please guide me the details step to configure soapui with ALM 11.
For example how to do a Post/Get request for defect entity, i am getting authentication error as "HTTP Status 401 - An Authentication object was not found in the SecurityContext" even though i am passing all the authentication parameters with the soap request.


Dobes said...

The reason cookies are not recommended is precisely because the browser sends cookies automatically with each request. So this allows some kinds of attacks (CSRF) where someone takes advantage of this fact to access secure information or perform actions on behalf of the user.

Unfortunately, the same applies to the Authorization header, if the login method is supported by the browser, so it is also vulnerable to CSRF and should be avoided.

A custom query parameter, POST parameter, or header is better. You can also use the Authorization header if you use a custom scheme not supported by the browser as it won't ever be automatically send by the browser.

Binh Thanh Nguyen said...

Thanks, nice tutorial