Python FastAPI Tutorial (Part 14): Password Reset - Email, Tokens, and Background Tasks
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
Python FastAPI Tutorial (Part 19): Deploy with Docker - Serverless Containers and Custom Domain
This tutorial demonstrates how to deploy a FastAPI application to Google Cloud Run using Docker containers, implementing security headers via middleware, leveraging multi-stage builds with the UV package manager for optimization, and configuring the container for serverless deployment with proper signal handling and non-root user privileges.
Python FastAPI Tutorial (Part 18): Deploy to a VPS - Security, Nginx, SSL, and Custom Domain
Corey Schafer demonstrates how to deploy a production-ready FastAPI application to a Virtual Private Server (VPS), emphasizing fundamental deployment concepts including security hardening, SSH key authentication, and health check implementation before moving to managed cloud solutions.
Python FastAPI Tutorial (Part 17): Testing the API - Pytest, Fixtures, and Mocking External Services
This tutorial demonstrates how to implement comprehensive testing for FastAPI applications using pytest with async support, covering critical setup patterns like environment variable configuration before app imports, using AsyncClient for async endpoints, mocking AWS S3 with Moto, and maintaining a separate PostgreSQL test database to ensure production parity.
Python FastAPI Tutorial (Part 16): AWS S3 and Boto3 - Moving File Uploads to the Cloud
This tutorial demonstrates how to migrate a FastAPI application from local disk storage to AWS S3 for production file uploads, covering S3 bucket setup, IAM security configuration, and Boto3 integration while maintaining separation between image processing and storage layers.