Issue a random one-time reset token, store only its digest, and enforce expiration and atomic consumption.
The examples introduce the underlying control before showing a verification and an application-level safeguard.
What You Will Build
Issue a random one-time reset token, store only its digest, and enforce expiration and atomic consumption.
Prerequisites
Use PHP 8.4 or newer, HTTPS for all authentication operations, and an application session or database where required. Example configuration values are placeholders, never production secrets.
Example 1: Basic Operation
Generate a one-time, random reset token and retain only its hash in storage.
<?php
$rawToken = bin2hex(random_bytes(32));
$tokenHash = hash('sha256', $rawToken);
$expiresAt = time() + 20 * 60;
// Store only $tokenHash and $expiresAt in the database; email $rawToken.
echo strlen($rawToken);
Example 2: A Different Use Case
Validate the token format before a database lookup.
<?php
$rawToken = $_POST['token'] ?? '';
if (!is_string($rawToken) || !preg_match('/^[a-f0-9]{64}$/D', $rawToken)) {
http_response_code(400); exit;
}
$lookup = hash('sha256', $rawToken);
// Look up $lookup in a transactional database operation.
Practical Example: Checking the Result
Ensure consumption and password change are one atomic, one-time operation.
<?php
$newPassword = $_POST['new_password'] ?? '';
if (!is_string($newPassword) || strlen($newPassword) < 12) { http_response_code(400); exit; }
$newHash = password_hash($newPassword, PASSWORD_DEFAULT);
// Inside a database transaction, SELECT the matching unexpired token FOR UPDATE.
// Update the user's hash and mark the token consumed in the same transaction.
// Check that exactly one row was affected; then commit and revoke old sessions.
// The complete flow must use database locking and anti-enumeration responses.
Important Behavior and Edge Cases
Avoid account enumeration; lock or transactionally consume tokens and revoke old sessions when the password changes.
Enforce controls on the server, test denial paths and do not assume that a snippet alone implements an entire production workflow.
Comparison with Related Functions
| Approach | Key distinction |
|---|---|
| PHP Password Reset Flow with Expiring Tokens | Issue a random one-time reset token, store only its digest, and enforce expiration and atomic consumption. |
| Related technique | Email verification links and password-reset links require different actions and scopes. |
Common Beginner Mistakes
| Mistake | Correct approach |
|---|---|
| Confusing this operation with a neighboring cryptographic or security mechanism | Email verification links and password-reset links require different actions and scopes. |
| Ignoring a security prerequisite or failure case | Avoid account enumeration; lock or transactionally consume tokens and revoke old sessions when the password changes. |
Key Takeaways
- Issue a random one-time reset token, store only its digest, and enforce expiration and atomic consumption.
- Avoid account enumeration; lock or transactionally consume tokens and revoke old sessions when the password changes.
- Email verification links and password-reset links require different actions and scopes.
Apply this behavior to a real application only after confirming the required extension, configuration and failure handling on the deployment runtime.