Skip to content
This repository has been archived by the owner on Nov 7, 2022. It is now read-only.

Generate secure tokens for use in emails (password reset, signup verification)

License

Notifications You must be signed in to change notification settings

fusionspim/php-email-tokens

Repository files navigation

PHP email tokens

Used in password reset (or sign up verification) emails, these need to be:

  1. Entirely random
  2. Short, containing only simple (0-9, A-Z and a-z) characters (to avoid email problems)
  3. Expiring within a short period of time (though still dependent on security of users mailbox)
  4. Deleted once used and/or expired (this bit is down to you!)
  5. Hashed when stored in the database (like passwords, so useless if read via SQL injection or worse)

Sample code for forgot_password.php

$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.

Sample code for reset_password.php

$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  
}

Options

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]);

Helpers

There are two helper functions:

$token->getExpiryMinutes(); // useful to mention in your email message
$token->getTokenLength(); // not sure what you'd use this for!

Credits

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! :-)