Used in password reset (or sign up verification) emails, these need to be:
- Entirely random
- Short, containing only simple (0-9, A-Z and a-z) characters (to avoid email problems)
- Expiring within a short period of time (though still dependent on security of users mailbox)
- Deleted once used and/or expired (this bit is down to you!)
- Hashed when stored in the database (like passwords, so useless if read via SQL injection or worse)
$token = new EmailToken;
$token->getEmailToken(); // include in the link you email the user (don't store anywhere!)
$token->getDatabaseHash(); // store against the user (128 character string) along with `tokenCreated`
Tip: better to put the user in a queue, then generate tokens/emails in a worker/cron.
$token = new EmailToken;
$user = loadFromHash($token->hashFromToken($_GET['token'])); // loadFromHash() is pseudo code, your bit!
if ($user && $token->stillValid($user->tokenCreated)) { // DateTime/Carbon parameter (or validate in your SQL query)
// show password form, delete hash/expiry stored against the user
} else {
// show generic/non-revealing 'Sorry, that token is no longer valid' message
}
An array can be passed in the constructor to override defaults:
- Token expiry period: the 15 minute default allows for email delivery delays, but lowers the risk of emails sitting around in a possibly unattended email client
- Token length: the 24 character default is nice and short for emails, but gives ~10,000,000,000,000,000,000,000,000,000,000,000,000,000,000 combinations for the 62 case-sensitive alphanumeric characters used - impossible to brute-force successfully (20 or more is recommended)
new EmailToken(['expiryMinutes' => 60]);
new EmailToken(['tokenLength' => 30]);
new EmailToken(['expiryMinutes' => 60, tokenLength' => 30]);
There are two helper functions:
$token->getExpiryMinutes(); // useful to mention in your email message
$token->getTokenLength(); // not sure what you'd use this for!
Comments, advice and code from Martin Stoeckli were invaluable in getting my knowledge and understanding to the point of being happy with all this - thanks Martin! :-)