Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 

110 thoughts on “Creating a Secure Login System the Right Way

  1. Thank you Tinsley for publishing this. It’s been difficult to find an easy to read intro to a basic login system. This is great. Best wishes!!

  2. First of all I wanna thank you for this post.
    I find it very usefus and clear, but I’ve a little security related question: hashing the password in the db make it really undiscoverable in any way. This is a real good thing. But what happens to the form data (username and password) between client and server?! I mean: unless you don’t use an https connection this data travels in plain text and can be easily sniffed.
    So my question is: there’s a way to encrypt data BEFORE send’em? (maybe with javascript?!)

    After my question I want to say to all those who criticize this post that I think these resorces need to be contextualized in your knowledge. If you don’t have the right PHP or programmin’ basis you really don’t understand a word of what you can read here!!! I say this because I’m not a programmer, only an enthusiast with a little PHP and programming basis. Anyway I’ve realized what I’ve read in this post in about 5 minutes… I apologize for my honesty but I think that first of all u’ve to say “Thank’s for sharing!” and then you can give your constructive contribution.
    Cheers!!!

    • But what happens to the form data (username and password) between client and server?! I mean: unless you don’t use an https connection this data travels in plain text and can be easily sniffed. So my question is: there’s a way to encrypt data BEFORE send’em? (maybe with javascript?!)

      The data is sent unencrypted so yes someone listening in could retrieve your raw password. The solution is to use ssl.

      If you needed to you could use javascript to encrypt the form data and decrypt it server side. You would need to use some kind of public key encryption (ex RSA). Basically you would use the public key to encrypt all of the form data and then server side you would use the private key to decrypt it. Someone intercepting the request wouldn’t be able to decrypt the form data without the private key. You would also need to use a nonce to prevent replay attacks (which ssl also protects against).

  3. This would be a great tutorial if it were more complete, but for someone new into PHP, it’s absolutely useless. It’s like bits of code splashed around on a page, no direction nor bearing. I think people would appreciate a direct link to a ZIP instead of this. Stingey coders…

  4. This evening I’ve been researching secure login and registration practices and this one is exactly what I’ve been looking for — great well written article. Thanks

  5. Hello there :)

    I really like this article and will surely help me with some security issues i currently have for my project.

    I still have a “small” question, that you might be able to answer:
    What if I need multiple logins at the same time? Can i still use the $_SESSION variable or should I use $_COOKIE insead?

    I hope you can help me :)

    Sincerely,
    I.M.

    • Don’t use cookies. Cookies are stored client side and are sent to the server with each request. Session data is stored on the server. Out of the box PHP uses a cookie to identify each user with their particular session, but this does not allow session data to be manipulated; storing all of the data in cookies would.

      What do you mean by multiple logins? Do you mean having multiple users logged into your site at once? If so the answer is yes, you can use sessions.

  6. really nice tutorial, was very helpful! Could you be a liitle more specific on this: ” I don’t recommend, for example, using header() to bounce your users around to different pages”

    What methods are recommended?

    • What I meant by that is that you shouldn’t be redirecting users from page to page if you don’t have to. The php file that generates your login form should be the same one that processes the data. This way if there is an error (ie incorrect password) you don’t have to redirect the user back to the login.

  7. Thank you for the tutorial!

    I had my login system already but I had doubts if it was secure or not. This helped me make the system a little more secure.

  8. nice but am looking for a loin script that need: email + password only no username.

    If you find one on the net please email me.
    thanks.

  9. One thing I learned when I built a registration system. People get confused by the difference between registering as new or just logging in. For the application I built it was just better to give the user one form, if they were already registered then they were considered logged-in, if they were new, then they were treated as a new user. What security issues would you see in simply providing a single form with the double password for both new and registered?

    • I’m not too sure that using a single form is the solution to people being confused; maybe have a more prominent registration link? Wouldn’t using a single form mean asking users to input their password twice every time they log in? Also, how would you distinguish between someone trying to register with a taken user name and that user logging in?

      As far as security goes, I don’t think there is anything inherently insecure about it, but I do think it’s somewhat cumbersome to deal with (both for the user and the person implementing it).

  10. This was great! I’m a novice and was still able to set this up on my site. I just have one question:

    What happens if my users forget their password? If the actual password is not stored in the database, then how could I ever retrieve it?

    Thanks!

    • You can’t retrieve a hashed password. You can reset the password. Just generate a random string, hash it, store that hash in place of the old hash, and email the new password to the user.

      Any site that allows you to retrieve your password is storing raw passwords, which is a bad idea. If anyone were to gain access to the user database they would have all of the users’ passwords.

  11. Hi there! Thanks for the tutorial! However, I’m trying to fix the logout() bug which i’m encountering right now. After trying to log out, i get this error: Undefined index: valid in … I believe this is happening because valid is now null? after logging out, is there a work around or something simple that i might be missing to fix this issue? thanks!

    • i forgot to add, this bug shows both the !isLoggedin content and the content that should be showing after logging in.

    • actually, if anyone is having trouble with this, try adding isset to valid in the function isloggedin! hope this helps! sorry for adding so many comments ;D

    • That’s not an error, it’s a notice. A script can still function as intended while still generating notices. That being said the following will not generate a notice:

      function isLoggedIn()
      {
          if(isset($_SESSION['valid']) && $_SESSION['valid'])
              return true;
          return false;
      }
      
  12. Hello. Can you explain how you make your links have no page title in them? I’d like to my site do that as well so when I pass variables with ‘get’, people can’t see them. I used something in htaccess once on a wiki but it didn’t seem to work.

    I’ve looked for info on this, but I think I’m searching for the wrong key words. So, if someone types mywebsite.com/Foo , how do I get it to treat the url like mywebsite.com/Foo/index.php or mywebsite.com/Foo.php or mywebsite.com/index.php?pagename=Foo – any of those while just showing the /Foo version in the url bar and allowing bookmarks to be written as just /Foo ?

    I am posting this here because the login system stuff is leading me to that challenge. Thanks very much!

    • htaccess is the way to go. I haven’t tested any of these:

      For website.com/foo -> website.com/foo.php

      RewriteEngine on
      RewriteRule (.*) $1.php [NC]
      

      For website.com/foo -> website.com/index.php?pagename=foo

      RewriteEngine on
      RewriteRule (.*) index.php?pagename=$1 [NC]
      

      For website.com/foo -> website.com/foo/index.php

      RewriteEngine on
      RewriteRule (.*) /$1/index.php [NC]
      

      I recommend you read this:
      http://corz.org/serv/tricks/htaccess2.php

  13. Hello. I am finding this article helpful, but what I don’t understand is the header(location: login (or register)_form.php). Are we meant to replace these links with other links? And if we don’t, what are we meant to put in those files? This has been skipped…

    • It depends on how you implement your user management system. For example if a user inputs incorrect login information you should direct them back to the login form. Where ever that may be. Note that by ‘direct them’ I don’t necessarily mean use header to bounce them to another page. It is possible (and practical) to have your login form and your form processing components in the same script. For example:

      if($_SERVER['REQUEST_METHOD'] == 'POST')
      {
           /*
           * process login information.
           * if correct redirect to whatever landing page you are using for users
           * if incorrect set and error message and display the login form
           */
      }
      //Display the login form here
      
      • Hi, I noticed you used if($_SERVER['REQUEST_METHOD'] == ‘POST’){}
        I have in many cases used if($_POST){} or if(isset($_POST["variablename"])) to check if a (method=”POST”) form was submitted.
        Is your method better/safer and why in that case?
        Does it prevent people from creating their own form (on their own web page) and submit a form like that? That’s something I have worried a bit about.
        Been trying to find a good answer online but without success.

        • All three methods will work, but there are some subtle differences.

          if($_POST) works because an empty array casts to false (note that $_POST is always set even if the request method is not post). if(isset($_POST["variablename"])) will work so long as that variable is set. Note that it isn’t actually checking if the request is a post request, only if that particular field is set.

          I wouldn’t say any of the are ‘the best’. I tend to use if($_SERVER['REQUEST_METHOD'] == ‘POST’), because that’s the one I tend to use.

  14. I’m trying to follow along this tutorial. The only problem is I don’t know where I’m putting some information. I think thats why people are asking for a zip of this file. :(

    I’m an idiot.

    • I still stand by my decision not to include a zip of the code I posted. When you develop your own user management system, your code is going to have to integrate with the rest of your application. Obviously it is impossible for me to write code that takes that into account, so simply dropping my code into your site is either not going to work correctly, or is going to be difficult to maintain. In other words, you can’t develop an application component in a bubble. You need to take into account how it will interact with the rest of your code.

      If you can point out more specifically what you don’t understand I can try to explain it more precisely.

  15. There’s one thing I don’t understand: in which file (and where) do I put the functions for the sessions to work? Someone asked for a zip before and I really understood the answer about having to update the zip, but could someone post a zipfile none the less, as the tutorial itself isn’t enough for me to fully understand what goes where…

    • You can put the function definitions anywhere so long as they are included before they are called.

      The main reason I won’t upload a zip file is not because it would be tedious to update it every time I modify this tutorial (though that is a contributing factor). The main reason is that I don’t want people to just copy and paste this code into an application. My goal is to demonstrate the concepts.

  16. ignore my previous comments please =D there was a problem with the registration php Part 2 that you had written! Instead of this:

    $hash = hash('sha256', $pass);

    it should be:

    $hash = hash('sha256', $pass1);

    because pass isnt a variable at all! pass1 or pass2 are the input!

  17. I’m trying to incorporate this login system but login always fails. it takes me to the login failed page. I thought i did something wrong but then i made a page to show the Hash generated from the login page and one that shows the one stored in the database. somehow they dont match. i think it may have to do with the salt so what do you think?

  18. Great article, concise, well written.
    I love that you respond to comments.

    It seems to me worth pointing out – (your script does not suffer from this) – with the most amazing log-on page, if you then on the rest of the site, just check the cookie “logged_in=yes” … then all an attacker needs to do is try a bunch of cookies until they find “logged_in=yes”.

    To counter this, you say in your database “user is logged on for 15 minutes after x time”. Then you reduce the window of opportunity.

    You could also (which you have) recorded the IP of the user who logs in, but then this would have to be stored in a cookie too. As you say, this can be read, in transit, over http (but not https). (id be interested to know more about that), but spoofing an IP doesn’t get you very far because all the responses are sent THERE and not back to the hacker with the spoofed IP [but you could potentially get the script do 'do things' as long as you don't need an answer].

    My point is, that without a log-out, i think that a hacker could simply modify their cookies until they found something which worked (i’ve seen ‘secure’ tutorials with this weakness)

    another of my points is, that without being able to store cookies on the clients computer, the only way you can work a log-in system is to put the username and password into every link on the page (tailored to each signed in user), and to run the whole thing is HTTPS ?? is this correct?? or rely on the IP of the user – but this could be the same for hundreds of users from large buildings, which is not acceptably secure?? without cookies, or HTTPS, is it possible to securely log-somebody in?

    I might also put a time-delay on any password page, to reduce the trys/per time of a brute-force attack. Possibly it’s worth saying “this IP can only contact this page 10 times, then i refuse it”. ??

    I don’t know what i’m talking about by the way.

  19. Awesome thanks. I’m planning to script a little php based game in the future whenever I get back into learning PHP all over again, so this will definitely help me to not only create a secure login for my game, but can possibly help me secure existing login systems to my websites.

  20. Very nice overview. I realise that you didn’t intend this to be copy-and-pasted into production, but is there any reason why you chose a 3-character length for the salt? You’d only need 16^3=4096 rainbow tables for the salt to be overcome, which isn’t inconceivable at all. It’s so fast that you might as well set it to 64 characters or so, maybe by combining a couple of MD5s. And you could make up some of the lost time by changing the password schema from VARCHAR(64) to CHAR(64) :P

    • That would be the case if we were just appending the salt to the password like this:

      $hash = hash('sha256', $password . $salt);
      

      Since we are rehashing like this:

      $hash = hash('sha256', $userData['salt'] . hash('sha256', $password) );
      

      it isn’t an issue.

      • An attacker would just need to know your very basic algorithm for rehashing then he can set up his tables as such.

        My point, if indeed I have one, is that the computational time for SHA-2 hashes is so low that you might as well just iterate a few more times. Even computing 500 or so hashes per pass wouldn’t be a problem – it takes a matter of milliseconds even on low-end servers. But taking 500 times longer to produce the tables really is a problem.

        It’s also good practice to include the salt in every rehash, rather than just making a straight hash of $password for the first hash. This reduces the number of collisions quite significantly.

        • Okay I see what you’re saying now. When you mentioned rainbow tables my mind immediately jumped to general purpose rainbow tables, which wouldn’t really be of any use here.

          You raise a very valid point. There are better approaches that yield better brute force resistance. I have been meaning to rewrite the hashing portion of the article to use crypt. This allows you to specify the number of rounds in the algo.

          crypt('laskdjfl;j', '$5$rounds=5000$asldkjflj$');
          
          • first, thanks to tinsley and everyone else who commented.

            tins, any update on including crypt() into the article? i’d like to use it. to see how you do it would be a huge help.

            john h

  21. Hello and thanks for a great article.

    I have created a login system where I have used several ideas from your good blog, so thanks :) Now I also need to making a ‘remember me’ feature. Thus making a function which store a cookie, which then will login the user.

    I’ve done this by storing a cookie, which keeps the user ID and “hash(‘sha256′, $saltTemp . hash(‘sha256′, password))”, where the $saltTemp value is not the same salt value as used when the user manually login. This $saltTemp is replaced each time the cookie is used to login, so that a cookie only can be used once (to login).

    Now I am afraid that it becomes too easy to find the original password if some can steal enough cookies.
    So my question is, are there any problems with this model? it is a secure model?

    • Given the output of hash('sha256', $saltTemp . hash('sha256', password)) there is no way for an attacker to derive the password other than brute force, which would mean they would need to know the value of saltTemp. One thing you may want to do is also include the user’s IP address in the hash:

      hash('sha256', $_SERVER['REMOTE_ADDR'] . $saltTemp . hash('sha256', password))
      

      Even if someone intercepted a cookie they would have to have the same IP address in order for the hash generated by the server to match.

  22. hii… i have a question… i have secure my site registration at three levels… 1. email authentication – mean our registration form send email to user email address for authentication. user have to follow the link we send into this email. 2. after that user follow this link through that email and reaches to our registration page. where he gets a complete form to fill up for the registration. Now on this page i am using CAPTCHA code to know the user is a machine or human. 3. I also put a readonly user IP address for the completion of registration.

    Now the problem i am facing is by one hacker… he is registering on my site since two months and his ip is hidden whenever he register on my site. I am not getting his ip address but yes i am getting the CAPTCHA code he write at the time of registration. “I am also storing the CAPTCHA code to my database”. As in the beginning i found that his IP address is hidden I then put a command for compulsary IP address at the time of registration. The IP address input box is readonly and it takes IP address of a visitor automatically. But still he is manage and overridding my registration form and able to register on my site without showing his IP address.

    Do you have any idea how he is doing this? And what should i do to block him? Any Suggestions?

    I am still working on it… reading articles … also read your articles… i am not a programmer and all above i mentioned are my few efforts…. but still not succeedeed to block this hacker…. ya the hacker is from china as the country he chooses is China.

    • Any form data, regardless whether it is read only, hidden, or restricted to discrete values (ie a select, checkbox, or radio field) can be modified by users. You need to validate that data server side.

      If I’m understanding correctly, there is no need for you to even include an IP field in the form. You can get the user’s IP server side from the $_SERVER array:

      $ip = $_SERVER['REMOTE_ADDR'];
      
  23. Great tutorial, thanks for putting this together! I am totally new to all this and you clearly answered a number of questions I had (eg preventing brute-forcing the hash by using the salt etc…) One slightly related question: at the end you say “I don’t recommend, for example, using header() to bounce your users around to different pages; there are better methods that reduce the number of page loads and give the user a more fluid experience”

    I was curious – what are the other methods for bouncing the user around (since I have just been using header(), and would love to hear a better way)

    Thanks!

    • In the example, when a user registers the script that processes the information is called register.php, while the script that contains the form is called register_form.php. If the user fails to input a certain field then they are bounced back to register_form.php. This is a waste of bandwidth and time. register.php and register_form.php should both be the same script. For example

      if($_SERVER['REQUEST_METHOD'] == 'POST')
      {
           //handle registration processing
      }
      //display registration form
      

      There are certain cases where it makes sense to use header to redirect a user. For example if someone attempts to access a restricted part of a site you would want to redirect them to a login page.

  24. Tell me whats more secure in adding a salt with it? You are still sending the password unencrypted over the line. Whats more secure in sending the password to the server and hash it with known salt then just hashing it with sha1 or md5?

    • Salting prevents the use of rainbow tables. A rainbow table is just a table containing strings and their hash values. For instance if you had a rainbow table and the sha1 hash of a string and you wanted to find the value of that string you could just look up the hash in the table and find a corresponding string value.

      In addition to this it makes it nearly impossible to brute force the hash unless you have the salt.

      By the way, md5 is not intended to be used as a password hashing algorithm. It is very easy to generate collisions for md5 hashes.

  25. I have been reading about and implementing pieces of: cookies, sessions, storing user login info in databases, salt, encyption algorithms, SSL certificates, data integrity policies, good/valid/invalid data, data filtering, and all the attacks (XSS, SQL injection) and how to mitigate them, but was wondering how to hook it all together. This example is perfect! Thanks for taking the time to put this together.

  26. Thanks for the excellent article- there are some subtleties I didn’t know about like session_regenerate_id.
    NOW- I need to implement remember me (auto login) the “right” way! That would be a nice tutorial. Thanks!

  27. Great Article… The only question that I have is would you put a username and password to the database into a file.

    Would people be able to create there own users if they used a site copier.

    • I’m not quite sure what you are trying to say.

      Are you asking if you can use a flat file to store user info? The answer is yes but I wouldn’t recommend it.

      I’m also not sure what you mean when you say would you be able to create users with a site copier. I’m not sure what a “site copier” has to do with user management.

      • I’m fairly certain the gentlemen is assuming that someone using some script to ‘wget’ or ‘cURL’ each page in a directory would attain the ability to connect to your database via perusing the PHP code {for database info}; as you well know, he is mistaken. Unless there is some way to directly ‘download’ a PHP/CGI/JS document without first parsing it outside of direct FTP/SSH access that I’m not aware of, that is…

        Also, thanks for the excellent tutorial!

  28. Hi, great article! It’ll help me start to create an admin login system for a CMS I’m building from a variety of tutorials.

    Anyway, here’s my question…

    Using an OOP approach as you have above, what would the best way of creating a OOP templated admin area be? Could you advise? I envisage an admin login page which opens out into an admin cpanel with links to different aspects of my CMS.

    Any help would be awesome! Cheers, RJP1

    • Using OOP doesn’t change much with regard to the overall approach of a login system. In fact, in my opinion, there is no need to incorporate much of the code I posted into objects, with a few exceptions. Since PHP gives you a choice when it comes to using objects (unlike Java) I recommend you exercise your ability to make that choice and use it only when you feel it is appropriate or necessary.

      For instance, it is likely that you will have some kind of database class that will handle your database operations throughout your application. You may also have a user object that contains all of the information pertaining to a particular user. In this case, when a user logs in, you use the database object to run your queries and you create a user object that can then be stored in a session once the user is logged in. The bulk of the code will remain unchanged.

      I personally don’t see any advantage in meticulously incorporating all of the code into objects.

  29. This is a great article. Thanks a million.

    One thing I noticed though, on line 10 of the first part of “Logging In”, you included a semicolon in the string –
    WHERE username = ‘$username’;”;

    Thanks again man, it’s a HUGE help.

    • SQL statements end with a semicolon just like lines in PHP code do. Technically it isn’t required unless you are executing multiple statements, but I’m in the habit of always ending statements with a semicolon.

  30. Wow. Thanks. While I’ve figured most of this already, I needed something to launch me into actually implementing it in PHP. Great article.

  31. Forgive my lack of knowledge (still very new to this), but when the user posts the login form is the login information passed to the server in clear text to be processed?

    In a standard implementation would these pages then need to be run inside a secure connection, or is there some inherent security that I’m missing?

    • Unless you are using ssl/tls (HTTPS) data sent over the network will be unencrypted. In most cases, whether or not you are using https is transparent to PHP; code that works for http connections will work for https as well. In most cases you would only use https if you were dealing with sensitive data: credit card transactions, accessing your bank account, etc. Large sites such as facebook tend to use https as well.

      To answer your question, you don’t need a secure connection to implement a login system, but it does add an extra layer of security. For a small site it is probably overkill and considering that a ssl certificate ranges from $100-$400 a year it may not even be feasible.

  32. Quote: “…And the main reason: This is not a working implementation. I don’t mean for you to copy this code and put it into production. It is meant to demonstrate the concepts. It is meant to be a reference for creating a login system of your own.”

    People who like me are looking for a login code, are hoping for a usable article, those who can code will do it themselves..

    • If you aren’t willing or able to take code and adapt it to your purposes, rather than copy and paste it out of the box, then why (and how for that matter) are you creating a login system? The article is meant to be a reference and assumes some coding experience. Knowing how to code isn’t the same as knowing how to create a login system (or anything else for that matter).

  33. Great article! Being new to implementing login systems, this article thought me the basics I needed to get started. Thanks for sharing!

  34. Your subject for this code is “Creating a Secure Login System the Right Way” yet you post insecure code. WTF? In your own words you say “you should never trust your users. Validate all user input, protect against SQL injections”, yet you don’t provide any sanitizing protection for the password input from the user. Newbies using your “secure” code will now be open to an sql injection attack.

    • Did you read the code carefully? The raw password never touches the database… it is hashed. There is no need to use escape_string or any other sanitizing on hashed data. The ONLY user input that touches the database is the username and that IS sanitized. In addition to this I point out PDO as an alternative to using the mysql_ family of functions, which is inherently more secure.

      • My bad! Feel free to delete my dumbass post. Thats what I get for writing and not sleeping. I take it all back!

        I blindly missed the WHERE username = ‘$username’ and assumed it was WHERE username = ‘$username’ AND password = ‘$password’ which WOULD have been a problem.

  35. Hi,

    Could you maybe post or email me entire script in a zip file?
    That would be really really great!

    Thanx in advance!
    /Nookie

    • Normally I would, but not in this case for three reasons:

      If I post a zip file of this script I will have to update it whenever I updated this post
      All I would be doing is copying the code I posted here into a few files
      …And the main reason: This is not a working implementation. I don’t mean for you to copy this code and put it into production. It is meant to demonstrate the concepts. It is meant to be a reference for creating a login system of your own.

  36. Thanks for the very good example. How ever I don’t know if any one experienced a crash with the registration form. I’m using Apache 2.2 with PHP 5 (WAMP configuration). It seems good practice to use mysql_close($conn); instead of mysql_close(); – Refer to register.php (part 4)

    • You are the first person to report a ‘crash’ as far as I’m aware. What exactly do you mean by crash? Is there an error message? Also, regarding mysql_close(), specifying the connection handle is only necessary if multiple connections are open, otherwise the behavior is identical to calling it without any parameters.

      • Hi Tinsley

        Sorry for not being specific. I tested it again with mysql_close(); Ite gave me the following error:

        Apache HTTP Server has encountered a problem and needs to close. We are sorry for the inconvenience. (One of those send / don’t send error reports).

        The error signature contains the following information:
        szAppName : httpd.exe
        szAppVer : 2.2.14.0
        szModName : php_mysql.dll
        szModVer : 5.3.0.0
        offset : 00002072

        I did debug the code and the error did occurred at the mysql_close();. I did a google search and found other developers had a problem with this in the past and stated to use the connection handle variable to prevent such an error.

  37. Pingback: A Supplement | Tinsology

  38. I’m getting a 40-digit value from the sha1 hash. I can make this work by modifying my db to accept it, but is there something I’m doing wrong that it’s not coming out 28 digits?

  39. And to follow up what Rob said, the maxlength attribute only asks the browser prevent the user form inputting a long string. The form data can’t be trusted since it can be cirucmvented.

  40. Great article… One correction though. Specifying a size attribute doesn’t keep the user from typing more text… The attribute you want to use is maxlength.

    Rob

      • I find this completely useless and a waste of time. You never mentioned where to save stuff and where to close the php tags and so on. I think this was just stupid.

        Kind Regards,

        John

        • I’m sorry you feel that way but when I wrote this my goal wasn’t to teach people programming 101 and how to create a login system. If you can’t figure out where to close the PHP tags you need to learn the basics first.

          • I completely disagree with John, this is a great article and id like to thank you for the time and effort you put into writing this. I knew the basics of sessions and logging in with databases etc, but had no idea how to do a salted password. this has helped so greatly. Thank you very much!

            • I slightly disagree with John, but massively disagree with the both of you. This is terrible ‘help’.

              You could have at least added ‘xxxx.php’ above each section to silently tell people which files they should be editing.

              • Depending on your implementation all of the user management code could be in a single file or spread out across several. Having me throw together several distinct file arbitrarily isn’t as helpful to someone integrating user management into their application as understanding the concepts is. I may not be doing the work for you, but that’s probably a good thing considering I can’t possibly know anything about the design of the rest of your application.