Python FastAPI Tutorial (Part 14): Password Reset - Email, Tokens, and Background Tasks

| Programming | March 30, 2026 | 1.52 Thousand views | 58:55

TL;DR

This tutorial demonstrates implementing a secure password reset flow in FastAPI using cryptographically secure hashed tokens stored in a database, asynchronous email sending via aiostmplib to prevent blocking, and Jinja2 templates for HTML emails, following security best practices like one-hour expiration and single-use validation.

🔐 Security Architecture & Best Practices 3 insights

Use cryptographically secure random tokens

Tokens must be unguessable and unpredictable to prevent brute force attacks, with a best practice expiration of 60 minutes or less.

Implement single-use token validation

Reset tokens must be immediately invalidated after use to prevent replay attacks, requiring database storage rather than stateless JWTs.

Prevent user enumeration attacks

The system should not reveal whether specific email addresses exist in the database when processing reset requests.

Asynchronous Email Infrastructure 3 insights

Use aiostmplib for non-blocking SMTP

Unlike Python's synchronous smtplib, aiostmplib operates asynchronously to prevent blocking the FastAPI event loop during email transmission.

Leverage FastAPI BackgroundTasks

Email sending should be handled as background tasks to ensure API endpoints return responses immediately without waiting for SMTP operations.

Configure secure email settings

Store SMTP passwords as SecretStr in Pydantic settings to prevent accidental logging, and hardcode frontend URLs to prevent attackers from manipulating request data to redirect reset links.

📧 Email Template Architecture 3 insights

Design email-compatible HTML templates

Email templates require inline CSS and table-based layouts rather than modern CSS Grid or Flexbox, as many clients strip style tags and ignore JavaScript.

Always include plain text fallback

Construct emails with both HTML and plain text versions using Python's email.message class to ensure accessibility across all email clients.

Render templates without request objects

Use templates.env.get_template() and manually render to string since email generation occurs outside the HTTP request/response cycle.

🗄️ Database Token Strategy 3 insights

Store token hashes, not plaintext

Persist only 64-character hashes of tokens in the database so that database breaches don't compromise active reset links.

Choose database tokens over JWTs

Unlike JWTs which cannot be invalidated before expiration without complex blacklists, database-stored tokens enable true single-use behavior and immediate invalidation by deleting records.

Implement cascade deletion for cleanup

Configure SQLAlchemy relationships with cascade='all, delete-orphan' to automatically remove reset tokens when a user account is deleted.

Bottom Line

Store password reset tokens as hashed values in your database with one-hour expiration to enable immediate invalidation after use, rather than using JWTs which cannot be easily revoked.

More from Corey Schafer

View all