71

I am currently working on a REST library for .net, and I would like to hear some opinions about an open point I have: REST and authentication.

Here is an example of an RESTful interface used with the library:

[RestRoot("/user")]
public interface IUserInterface
{
  [RestPut("/")]
  void Add(User user);

  [RestGet("/")]
  int[] List();

  [RestGet("/get/{id}")]
  User Get(int id);

  [RestDelete("/delete/{id}")]
  void Delete(int id);
}

The server code then just implements the interface and the clients can obtain the same interface through a factory. Or if the client is not using the library a standard HTTP request also works.

I know that there are the major ways of either using HTTP Basic Auth or sending a token to requests requiring authenticated users.

The first method (HTTP Basic Auth), has the following issues (partly web browser specific):

  • The password is transmitted with every request - even with SSL this has some kind of "bad feeling".
  • Since the password is transmitted with a request header, it would be easy for an local attacker to look at the transmitted headers to gain the password.
  • The password is available in the browsers memory.
  • No standard way to expire user "sessions".
  • Login with a browser interrupts the look and feel of a page.

The issues for the second method are more focused on implementation and library use:

  • Each request URI which needs authentication must have a parameter for the token, which is just very repetitive.
  • There is a lot more code to write if each method implementation needs to check if a token is valid.
  • The interface will become less specific e.g. [RestGet("/get/{id}")] vs. [RestGet("/get/{id}/{token}")].
  • Where to put the token: at the end of the URI? after the root? somewhere else?

My idea was to pass the token as parameter to the URL like http:/server/user/get/1234?token=token_id.

Another possibility would be to send the parameter as an HTTP header, but this would complicate usage with plain HTTP clients I guess.

The token would get passed back to the client as a custom HTTP header ("X-Session-Id") on each request.

This then could be completely abstracted from the interface, and any implementation needing authentication could just ask which user the token (if given) belongs to.

Do you think this would violate REST too much or do you have any better ideas?

Matthew Murdoch
  • 30,874
  • 30
  • 96
  • 127
Fionn
  • 10,975
  • 11
  • 54
  • 84

3 Answers3

64

I tend to believe that authentication details belong in the header, not the URI. If you rely on a token being placed on the URI, then every URI in your application will need to be encoded to include the token. It would also negatively impact caching. Resources with a token that is constantly changing will no longer be able to be cached. Resource related information belongs in the URI, not application related data such as credentials.

It seems you must be targeting web browsers as a client? If so you could investigate using HTTP Digest access authentication or issuing clients their own SSL certificates to uniquely identify and authenticate them. Also, I don't think that session cookies are necessarily a bad thing. Especially when having to deal with a browser. As long as you isolate the cookie handling code and make the rest of the application not rely on it you would be fine. The key is only store the user's identity in the session, nothing else. Do not abuse server side session state.

If you are targeting clients other than the browser then there are a number of approaches you can take. I've had luck with using Amazon's S3 Authentication mechanism.

This is all very subjective of course. Purity and following REST to the letter can sometimes be impractical. As long as you minimize and isolate such behavior, the core of your application can still be RESTful. I highly recommend RESTful Web Services as a great source of REST information and approaches.

Community
  • 1
  • 1
laz
  • 28,320
  • 5
  • 53
  • 50
  • In S3 example they share cryptographic key with clients - this is bad, isnt it? – Gill Bates Apr 10 '14 at 13:28
  • Like any sort of shared secret cryptography, it is essential that both parties maintain the secrecy of the key. In that regard it is no worse that symmetric cryptography. – laz Apr 22 '14 at 14:48
15

I agree with workmad3, if session life time needs to be maintained you should create a session resource. Post on that resource with user credentials (either basic authentication or credentials in the body content) will return unique session id. Delete on /session/{id} will log out the user.

If you want to control the session expiry time. When creating new session (post on session resource) the server will set a cookie on the response (using standard set-cookie header). The cookie will contain expiry time. The cookie string should be encrypted on the server, so only the server can open that cookie. Every consequent request to the server will send the session cookie in the cookie header. (it will be done automatically for you if your client is a browser). The server needs to "renew" the cookie for every request, i.e. create new cookie with new expiry time (extend session's timeout). Remember to clear the cookie when the user calls delete on the session resource.

If you want your application to be more secured you can store the client IP in the cookie itself, so when a request arrives the server can validate that it was sent from the "original" client. But remember that this solution can be problematic when proxies are involved, because the server might "see" all the requests as coming from the same client.

LiorH
  • 18,524
  • 17
  • 70
  • 98
  • I don't see a problem with proxies here. It's just that the added security is reduced by the fact that some clients appears to be the same. The cookies should also be [httpOnly](http://en.wikipedia.org/wiki/HTTP_cookie#HttpOnly_cookie). – maaartinus May 17 '14 at 11:08
4

The rest authentication I've seen treats the sessions as a REST resource for creation, destruction etc. and then the session ID is passed to and fro. The ones I've seen tend to use the session cookie for this as it's the only way to secure it really. If you pass the session id in the URL, you don't have any way of really authenticating it came from the correct client.

Authentication is a tricky problem with REST though, as it requires some form of state to be kept outside the URL which infringes upon REST principles of the URL being all that is required to represent state.

workmad3
  • 25,101
  • 4
  • 35
  • 56
  • Since it will allways use SSL if not used internally in a secured network and using UUIDs for sessions the where it came from should not be a problem. And what hinders someone to fake the cookie? – Fionn Jan 19 '09 at 18:34
  • 3
    I wouldn't say that having the URI be all that is required to represent state is a principle of REST. Rather, having resources be addressable and all of the application state contained in the request seems like a better way to state it. – laz Jan 21 '09 at 20:25
  • You would secure the cookie with a MAC, e.g. the server has a secret and would hand out to the client the following session-token: _ where mac is constructed as SHA1(_) When a client sends a token _ the server must check if _ equals – ordnungswidrig Feb 11 '10 at 09:15
  • 18
    In these discussions, it is important to distinguish __application state__ (session state) from __resource state__. In a RESTful architecture, resource state is stored server-side, whereas application state is stored client-side. [http://www.infoq.com/articles/mark-baker-hypermedia] – user359996 Oct 09 '10 at 20:04
  • @user359996 The url you posted seems to be broken. Can you provide a new link to the same ? – Bharat Khatri Jul 25 '13 at 09:07
  • Try this: http://web.archive.org/web/20120514080338/http://www.infoq.com/articles/mark-baker-hypermedia – user359996 Jul 25 '13 at 12:40
  • Or just remove the extra square bracket that was added to the URL by accident: http://www.infoq.com/articles/mark-baker-hypermedia – Micah Henning Sep 09 '13 at 22:20
  • @Fionn: **1.** Everyone in your room can read your URL. Try this with cookies. **2.** Both URL and ordinal cookies can be read by Javascript. That's why [httOnly](http://en.wikipedia.org/wiki/HTTP_cookie#HttpOnly_cookie) has been created. **3.** It's easy to let the token containing URL to sneak into a saved document by accident. I can see only risks and the only advantage seem to be following the principles more rigidly. – maaartinus May 17 '14 at 11:20
  • 1
    @maaartinus: Currently (as the question was asked "some" time ago) I would no longer consider using any session data as part of the URL, it seemed logical first but on a second view the risks are much too high. – Fionn May 20 '14 at 11:02