1

There are some ways which I am considering of.
1. using the user PK, the cookie value: {id}:{md5(id+salt)}
2. using the user email, the cookie value: {email}:{md5(email+salt)}
3. way 1 or 2 plus the password, like {id}:{md5(id+pass+salt)}, but this way will make a db select every time (select the password).

Is there any other good way of cookie based auth?

Awais Qarni
  • 17,492
  • 24
  • 75
  • 137
xdazz
  • 158,678
  • 38
  • 247
  • 274
  • 2
    Any reason to avoid sessions? – zerkms May 20 '11 at 03:17
  • @zerkms: RESTful implementation? :) – Demian Brecht May 20 '11 at 03:18
  • @Demian Brecht: how REST is related to cookies? All API's I've ever seen used get/post-parameters to pass authentication. – zerkms May 20 '11 at 03:22
  • @zerkms: It's arguable, but as sessions use server resources, it's not strictly RESTful. – Demian Brecht May 20 '11 at 03:25
  • @Demian Brecht: RESTful APIs don't use cookies neither. So still makes no sense for me. Btw, is database a server resource? So if RESTful application uses database (or any persistent storage) - it is supposed to be not restful?! – zerkms May 20 '11 at 03:26
  • @zerkms: Sessions violate RESTful design as it uses server resources. Cookies are valid as they're kept client-side and can be used to dictate state to the server. http://www.ics.uci.edu/~fielding/pubs/dissertation/net_arch_styles.htm#sec_3_4_3 – Demian Brecht May 20 '11 at 03:29
  • @Demian Brecht: 1) No one uses cookies in restful apis (would like to see any real usage otherwise) 2) Databases also makes application stateless – zerkms May 20 '11 at 03:30
  • @zerkms: You don't want to pass auth information (which is what the data in the OP is pertaining to) in URLs. As sessions are invalid to a RESTful design, that leaves cookies as the only (AFAIK) valid method of passing auth state information to the server. I actually did some research on this topic some time ago, which is why I had a speedy answer to your first question. Having said that, my answer *was* an educated guess (hence the question mark at the end) :) – Demian Brecht May 20 '11 at 03:33
  • @Demian Brecht: any real life examples of cookies usage in RESTful APIs? I don't believe it worth to reinvent a wheel and not to use OAuth (or other time-proven cookie-less solutions). – zerkms May 20 '11 at 03:35
  • @zerkms: You apparently don't understand OAuth: "OAuth allows you to share your private resources (photos, videos, contact list, bank accounts) stored on one site with another site without having to hand out your username and password." (quoted directly from their site). Please do some research on authentication methods in a RESTful implementation. My answer to your question was intended as a guessed answer. The intent was not to spark a debate which is *not* helping the OP *at all*. – Demian Brecht May 20 '11 at 03:39
  • @Demian Brecht: I **do** know that oauth is an *authorization* protocol, but it also supposed to be stateless. And I just asked - have you ever seen stuff you researched and talking about? – zerkms May 20 '11 at 03:41
  • @zerkms The customer wants the auth state to persistent for one year. And the session expired time is 30 minutes. Of course, a [remember me] cookie can make auto login after 30 minutes, but the customer just don't like this way. – xdazz May 20 '11 at 03:47
  • @xdazz: who is professional - you or your customer? Tell him that "don't like" is not enough to follow weird solution. – zerkms May 20 '11 at 03:50
  • @zerkms The site is using the db session now, so just use the cookie can release some db press. – xdazz May 20 '11 at 04:17
  • @xdazz: If you have issues with DB - then probably you need to solve them by choosing more performant session storage, like memcached. But not avoiding sessions at all. – zerkms May 20 '11 at 04:22
  • @Demian, @zerkms Could you please slug it out here: [Do sessions really break RESTfulness?](http://stackoverflow.com/questions/6068113/do-sessions-really-break-restfulness) :) – deceze May 20 '11 at 06:14
  • @deceze: I'm not guru of REST, I've never performed any researches lol )) – zerkms May 20 '11 at 06:17
  • You definitely want to use the password in the cookie hash. That way, if a user accidentally ticks the 'remember my login' checkbox in a library, it can invalidate that login (and all other remembered logins btw) changing his password. – Carlos Campderrós May 20 '11 at 08:45

1 Answers1

0

What you really want is:

  id:[some_int],
  session_token:[some_hash]

The session token is created only on the server, and is just a lookup key... importantly, paired with the user_id. It gets stored in a database, with an expiration date. Once that expiration is hit, you require a new login. You can set the timeout at any time... change the way you generate the keys, etc. You can also hav different classifications of auth tokens with different timeouts, etc.

On page load, you use the id and session token as queries into your session table, typically with a date rage selection (depending on your login business rules). If everything matches up, you're good. For extra obfuscation, you could use part of the user-agent.

How you generate the token doesn't matter in this case... an MD5(mktime()) is just as good as anything else.

The only time you need to worry about prebuilt formats is for auth_tokens, which could be used to bridge API gaps between applications & your Web service (doesn't sound like you need to worry about this).


Example login detection flow:

<?php
   session_start();
   if (array_key_exists('auth_user', $_SESSION))
   {
       // user already has a session.
   }
   elseif (array_key_exists('session_token', $_COOKIE))
   {
       $sql = 'SELECT * 
               FROM sessions
               LEFT JOIN users USING (user_id)
               WHERE sessions.user_id = %d
                 AND sessions.token = \'%s\'
                 AND [ some date argument ]
               LIMIT 1';
       // execute SQL.  If you get a user back, great.  Set up a session.
       if (!empty($user))
       {
           $_SESSION['auth_user'] = $user;
       }
   }
   else
   {
      // Not logged in.  Do what you want here (like show a login UI).
   }

Your Auth code should create the token, drop it into the DB, and set the cookie.

John Green
  • 13,241
  • 3
  • 29
  • 51
  • Do you mean the session table has a column 'id' for store the user id? And where to store the expiration date? the user table? – xdazz May 20 '11 at 05:47
  • Yes. The session table has at least 3 columns: id, token, and issue_date. The ID & Token are strongly paired -- only User A can ever use User A's token. – John Green May 20 '11 at 05:48
  • But the expiration of session is 30 minutes, how to persistent the auth state of one year? – xdazz May 20 '11 at 05:51
  • Also note... generally, the ID is indexed, but *NOT* a primary key. That way, the same user can keep tokens for different computers. – John Green May 20 '11 at 05:52
  • This isn't an apache 'session' (it has no bearing on $_SESSION, other than you probably want to invoke it once a user shows up with a proper id/key combination. This is a custom 'session' based on the DB. – John Green May 20 '11 at 05:53
  • Simply saying, when the session record is delete by the session gc after 30 minutes, the user need to login again? What the customer wants is to persistent auth for one year, but the session record's expiration is just 30 minutes. Sorry for my poor English. – xdazz May 20 '11 at 05:59
  • Look at my login detection flow.. just added. – John Green May 20 '11 at 06:00
  • Thank you very much for your code. I have understood this. But customer want to make persistent auth in different computers or browsers with same user. – xdazz May 20 '11 at 06:10
  • Exactly why the sessions.user_id field is not a primary key. You can have multiple sessions open for every user this way. – John Green May 20 '11 at 06:15
  • So when a user login twice in same browser, how to delete the old record? – xdazz May 20 '11 at 06:21
  • Shouldn't need to. The flow above first checks for the session, then the cookie. The old record can stay in the system pretty well forever, and can be used as a basis for high-end logging. If you feel you want to remove them for some reason, you can always run a cron job. – John Green May 20 '11 at 08:47