Let's clarify a few things first:
PHP sessions, in their default form are cookie based, I have an overview of how they work in another answer. But since they are cookie based, to me that says that if you are going to base your authentication and authorization workflow around cookies, go with normal cookies for everything - and just use sessions for what they are good for: session data persistence.
The circular login pattern you noticed is exactly why you should delete cookies on logout. Also, as @Morons writes, when a user clicks log out, expects to actually log out. It doesn't cancel out the auto-login feature, but one should be able to log out at any time.
Now, my auto login-approach goes something like this:
Which of course is pretty basic, but what is really important is the whole "cookie is valid" check. When a user successfully logins with the "remember me" option checked, I generate an auto-login token: A sensibly unique random string, most probably a salted hash.
That's the only thing I store in the cookie, nothing else nothing more. There is no actual need to store anything that could possibly identify an individual user in a cookie, you should avoid storing stuff like usernames and emails (even hashed). In my database, I have a simple token
table that basically stores:
- A user id,
- The token,
- An expiration date
And my check involves just checking against this table. The expiration date may seem like an overkill, as you can expire the cookie whenever you want but: You should treat everything that comes along with the cookie as user input, unsafe and easily faked. That includes it's expiration. And of course at log out I don't bother killing the cookie, I just set a NOW()
as the expiration date. Easy as pie, and I keep most elements of the check server-side, where it feels a little bit more safe.
In a recent project, I went a step further and added the check at every page request instead of storing something in a session to indicate an authorized session. Some may argue that the call to the database will lead to performance issues, but my 'token' table has grown to about 10 million tokens1 and still I haven't noticed any actual issue. Keep in mind that sessions involve file system access, that's almost never faster than a simple select
.
Of course, any cookie that stores anything related to authentication and authorization should be encrypted. And I'd recommend you always enforce secure cookies, with setcookie()
is as easy as setting the secure
parameter to true:
Indicates that the cookie should only be transmitted over a secure HTTPS connection from the client. When set to TRUE, the cookie will only be set if a secure connection exists. On the server-side, it's on the programmer to send this kind of cookie only on secure connection (e.g. with respect to $_SERVER["HTTPS"]).
1 I don't delete expired tokens for a variety of reasons.
Technically, only the target of the form needs to be a SSL protected page for the submission to be encrypted. I saw this done at a previous job where we had a login form in the header.
HOWEVER
By doing this you are losing the clarity that we've been telling users to look for. Users are instructed to look to the URL bar to see if the website is using an encrypted connection for their information. By having the page not delivered via SSL, users may mistakenly believe that their form (username and password) isn't encrypted either.
Furthermore, as pointed out by Craig below, if the page you're submitting from isn't encrypted, you cannot assert that the page has not been intercepted and altered. That familiar form that you know has always submitted to a HTTPS url may have been intercepted and altered before it was rendered.
Your best bet is to just offer SSL on all pages if you insist on having the login form in the header. SSL is relatively cheap to implement as far as server resources, and it gives your users the extra security they deserve.
Best Answer
Your solution will mostly be dependent upon the workings of that third-party web site.
If they support some kind of third-party security like OpenAuth you may be able to use that.
Perhaps you can wrap their web site in your own code. Do not redirect your user's browser to their site, but instead proxy the connection through your page. Then you can intercept the login page and provide credentials without the end-user even knowing that there was a login.
Provide individual accounts on that third party site. Probably not ideal, as now people have to manage their own credentials, but perhaps better than nothing.
Lastly, do be aware about the terms-of-service for the third-party site you are using. Given you are using it as part of your workflow, do they allow for that? Support it? Explicitly disallow it such that you could find yourself cut off?