What are the best current libraries/methods to authenticate users without the use of a CMS or heavy framework?
Responses should include suggestions for anything you
Implementing user authentication securely without relying on a framework (or third-party library, such as OpenID) to do it for you is not a trivial undertaking.
At a 10,000 foot overview, you have to decide:
password_hash() or scrypt are the way to go.The information in this answer is relevant and up-to-date as of May 9, 2015 and might be obsoleted by the conclusion of the password hashing competition
In general, usernames and email addresses are better than ID numbers.
There should be no security requirement to keep usernames secret, because in practice they will be leaked when someone tries to register anyway.
You can decide whether or not to treat email addresses as a secret. Users generally like not being exposed to spammers, scammers, and trolls.
You should use password_hash() and password_verify() unless you are sufficiently experienced with writing cryptography libraries to go above and beyond.
Sometimes developers like to get creative (e.g. adding a "pepper", which usually means pre-hashing or HMACing passwords with a static key) and go beyond the standard implementations. We ourselves have done this, but very conservatively.
For our internal projects (which have a much higher margin of security than most people's blogs), we wrote a wrapper around this API called PasswordLock that first hashes a password with sha256, then base64 encodes the raw hash output, then passes this base64-encoded hash to password_hash(), and finally encrypts the bcrypt hash with a properly-implemented encryption library.
To reiterate, instead of peppering, we encrypt our password hashes. This gives us more agility in case of a leak (we can decrypt then re-encrypt because we know the key). Additionally, we can run our webserver and database on separate hardware in the same datacenter to mitigate the impact of a SQL injection vulnerability. (In order to start cracking hashes, you need the AES key. You can't get it from the database, even if you escape to the filesystem.)
// Storage:
$stored = \ParagonIE\PasswordLock\PasswordLock::hashAndEncrypt($password, $aesKey);
// Verification:
if (\ParagonIE\PasswordLock\PasswordLock::decryptAndVerify($password, $stored, $aesKey)) {
// Authenticated!
}
PasswordLock:hash('sha256', $password, true);base64_encode($step1);password_hash($step2, PASSWORD_DEFAULT);Crypto::encrypt($step3, $secretKey);PasswordLock:Crypto::decrypt($ciphertext, $secretKey);hash('sha256', $password, true);base64_encode($step2);password_verify($step3, $step1);