So far so good.
- Encrypt passwords using PHP's password_hash() function.
Do you actually need to have your user's keep track of yet another user/password? Can't you use their internet's driver's license?
That said, assumming you can't or won't, make sure to use a good salt and a version of php that uses bcrypt (I believe it's default since 5.0).
- Generate a new token and delete the old one on every new login.
- Login user using a cookie, storing the users token
- Check cookie on each page load against a SHA1 hashed version of the token stored in the cookie.
- If the token is deleted from the database the user is logged out.
I assume you have an expiration time for the tokens and they are purged by a backend. What happens if the user is currently logged in and the backend detects the token expired?
There are several other things to consider.
CSRF
Be careful with CSRF on your login and logout forms. You don't want your users getting automatically logged out by third parties.
Actually, be careful with CSRF throughout the whole site.
Bruteforcing
Implement bruteforce measures on your login form and whatever backend it communicates to:
- Increasing delay for failed login attempts
- Mandatory captchas after a threshold of attempts
- Temporary ban by IP address after a threshold of attempts
Monitor each of this measures, ensure they don't cause troubles for your users.
Password recovery mechanisms
How will your users recover forgotten passwords?
Ensure your mechanism is secure and doesn't leak personal information of your users.
Information leak
Make sure not to leak information on failed login attempts. An error message like this:
Invalid user
Gives valuable information to attackers (they can tell whether a username exists or not).
It's not enough to have a generic error message. This is much more nuanced than it seems at first: if you take 2 seconds to reply for bad passwords but only 100 milliseconds for bad usernames you're leaking information.
See CVE 2006-5229 for a good example of this last attack.
Ease of use
Security at the expense of usability comes at the expense of security
Use standard field names for username/password so your users can comfortably use a password manager if they choose to.
OWASP
For more details read the OWASP docs on authentication.
OWASP is a must for all web developers.