Technical Articles & Tutorials

Email Verification Authentication System

Overview & Purpose

Traditional password-based authentication systems create friction for users while introducing security vulnerabilities through password reuse, weak passwords, and forgotten credentials. An email verification authentication system offers an alternative approach that balances security with usability while ensuring users provide verified contact channels.

This system eliminates passwords entirely, instead relying on time-limited verification codes sent to email addresses. The approach reduces fake accounts, ensures contactable users, and removes the burden of password management for both users and developers.

Core Functionality

User Registration Flow

Registration Process

1. User provides email address 2. System presents basic CAPTCHA challenge 3. System generates time-limited verification code (6-8 digits) 4. Code is emailed to user 5. User enters code to verify identity 6. Upon verification, account is created/authenticated

Authentication Flow

Authentication Process

1. User enters email (no password required) 2. System generates new verification code 3. Code is emailed to user 4. User enters code to authenticate 5. System creates authenticated session

Implementation Example

Here's a Flask implementation demonstrating the core verification system:

Email Verification Model

```python import secrets import string from datetime import datetime, timedelta from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class EmailVerification(db.Model): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(255), nullable=False) code = db.Column(db.String(8), nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) expires_at = db.Column(db.DateTime, nullable=False) used = db.Column(db.Boolean, default=False) ip_address = db.Column(db.String(45)) @staticmethod def generate_code(): """Generate a 6-digit numeric verification code""" return ''.join(secrets.choice(string.digits) for _ in range(6)) @classmethod def create_verification(cls, email, ip_address): """Create a new verification code for an email""" code = cls.generate_code() expires_at = datetime.utcnow() + timedelta(minutes=15) verification = cls( email=email, code=code, expires_at=expires_at, ip_address=ip_address ) db.session.add(verification) db.session.commit() return verification def is_valid(self): """Check if verification code is still valid""" return ( not self.used and datetime.utcnow() < self.expires_at ) def mark_used(self): """Mark verification code as used""" self.used = True db.session.commit() ```

Rate Limiting Implementation

```python from collections import defaultdict from datetime import datetime, timedelta class RateLimiter: def __init__(self): self.ip_attempts = defaultdict(list) self.email_attempts = defaultdict(list) def check_ip_limit(self, ip_address, max_attempts=10, window_hours=1): """Check if IP has exceeded rate limit""" now = datetime.utcnow() cutoff = now - timedelta(hours=window_hours) # Clean old attempts self.ip_attempts[ip_address] = [ attempt for attempt in self.ip_attempts[ip_address] if attempt > cutoff ] return len(self.ip_attempts[ip_address]) < max_attempts def check_email_limit(self, email, max_attempts=5, window_hours=24): """Check if email has exceeded daily limit""" now = datetime.utcnow() cutoff = now - timedelta(hours=window_hours) # Clean old attempts self.email_attempts[email] = [ attempt for attempt in self.email_attempts[email] if attempt > cutoff ] return len(self.email_attempts[email]) < max_attempts def record_attempt(self, ip_address, email): """Record a verification attempt""" now = datetime.utcnow() self.ip_attempts[ip_address].append(now) self.email_attempts[email].append(now) rate_limiter = RateLimiter() ```

Flask Routes

```python from flask import Flask, request, session, jsonify, render_template from flask_mail import Mail, Message import re app = Flask(__name__) mail = Mail(app) def is_valid_email(email): """Basic email validation""" pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' return re.match(pattern, email) is not None def send_verification_email(email, code): """Send verification code via email""" msg = Message( subject='Your Verification Code', recipients=[email], body=f'Your verification code is: {code}\n\nThis code expires in 15 minutes.' ) mail.send(msg) @app.route('/auth/request-code', methods=['POST']) def request_verification_code(): data = request.get_json() email = data.get('email', '').lower().strip() ip_address = request.remote_addr # Validate email format if not is_valid_email(email): return jsonify({'error': 'Invalid email format'}), 400 # Check rate limits if not rate_limiter.check_ip_limit(ip_address): return jsonify({'error': 'Too many requests from this IP'}), 429 if not rate_limiter.check_email_limit(email): return jsonify({'error': 'Too many requests for this email'}), 429 # Create verification code verification = EmailVerification.create_verification(email, ip_address) # Send email try: send_verification_email(email, verification.code) rate_limiter.record_attempt(ip_address, email) return jsonify({ 'message': 'Verification code sent', 'expires_in': 900 # 15 minutes in seconds }) except Exception as e: return jsonify({'error': 'Failed to send email'}), 500 @app.route('/auth/verify-code', methods=['POST']) def verify_code(): data = request.get_json() email = data.get('email', '').lower().strip() code = data.get('code', '').strip() # Find valid verification verification = EmailVerification.query.filter_by( email=email, code=code ).first() if not verification or not verification.is_valid(): return jsonify({'error': 'Invalid or expired code'}), 400 # Mark code as used verification.mark_used() # Create user session session['authenticated'] = True session['email'] = email session['login_time'] = datetime.utcnow().isoformat() return jsonify({ 'message': 'Authentication successful', 'email': email }) @app.route('/auth/logout', methods=['POST']) def logout(): session.clear() return jsonify({'message': 'Logged out successfully'}) ```

Security Considerations

Rate Limiting Strategy

Rate Limiting Rules

• **IP-based**: 10 requests per hour per IP address • **Email-based**: 5 verification emails per day to a single address • **Progressive timeouts**: Increasing delays for repeated failed attempts

Code Design Principles

Code Design

• **Length**: 6-8 digits (sufficient entropy while user-friendly) • **Expiration**: 10-15 minutes (balance security and usability) • **One-time use**: Codes cannot be reused once verified • **Numeric only**: Easier to type, especially on mobile devices

Anti-Abuse Measures

Security Measures

• Basic CAPTCHA on initial requests • Email domain validation (MX record verification) • Pattern detection for unusual authentication behavior • Comprehensive audit logging of all authentication events • Automatic cleanup of expired verification codes

Feature Priority Matrix

Feature Priorities

| Feature | Importance | Complexity | Rationale | |---------|------------|------------|----------| | Email verification | High | Low | Core functionality | | Rate limiting | High | Medium | Critical for preventing abuse | | CAPTCHA integration | High | Low | Simple bot prevention with high impact | | Code expiration | High | Low | Basic security requirement | | Audit logging | High | Medium | Essential for security monitoring | | Email domain validation | Medium | Low | Prevents obviously invalid emails | | Progressive timeouts | Medium | Medium | Enhances security without major UX impact | | Mobile-friendly design | Medium | Medium | Important for user adoption | | Account linking options | Low | High | Nice-to-have for future expansion | | Admin control panel | Low | High | Can be added later as needs arise |

Design Decisions & Rationale

Why Email Verification vs. Passwords

Benefits of Email Verification

• **Reduced friction**: No password rules to follow or remember • **Improved security**: Eliminates password reuse vulnerabilities • **Verified users**: Ensures real email addresses and contactable users • **Reduced support burden**: Eliminates password reset flows

Why 6-8 Digit Codes

Code Length Rationale

• **Security balance**: Long enough to prevent brute force, short enough to type • **User familiarity**: Similar to other verification systems (2FA, banking) • **Mobile optimization**: Numeric-only codes are easier to type on mobile devices • **Accessibility**: Simpler than complex character combinations

Why Basic CAPTCHA

CAPTCHA Benefits

• **Low friction**: Minimal impact on legitimate users • **High effectiveness**: Stops most automated attacks • **Accessibility**: Simpler CAPTCHAs maintain better accessibility • **Cost effective**: Reduces need for complex anti-abuse systems

Why Short Expiration Times

Expiration Time Benefits

• **Security**: Minimizes window of vulnerability • **User expectations**: Users expect to complete verification immediately • **Database efficiency**: Expired codes can be purged quickly • **Reduced support issues**: Clear expectations about code validity

Implementation Considerations

Production Deployment Notes

• Configure reliable email delivery service (SendGrid, AWS SES, etc.) • Implement proper database indexing for email and timestamp queries • Set up monitoring for email delivery failures and authentication patterns • Consider implementing email reputation checking for additional security • Plan for scalability with distributed rate limiting if needed

User Experience Enhancements

• Auto-focus on code input field after email submission • Show countdown timer for code expiration • Provide clear error messages for different failure scenarios • Allow code resending with appropriate delays • Consider magic link alternatives for users who prefer them

Conclusion

Email verification authentication systems provide a compelling alternative to traditional password-based authentication. By eliminating passwords, these systems reduce user friction while ensuring verified contact channels and improving overall security posture.

The key to successful implementation lies in balancing security measures with user experience, implementing robust rate limiting, and maintaining clear communication about the authentication process. When properly designed, email verification systems can significantly reduce fake accounts while providing a more streamlined user experience.

This approach is particularly well-suited for applications where verified email contact is essential, where user convenience is prioritized, or where the security risks of password-based authentication outweigh the benefits of traditional credential storage.

About

Why fear those copying you, if you are doing good they will do the same to the world.

Archives

  1. AI & Automation
  2. AI Filtering for Web Content
  3. Web Fundamentals & Infrastructure
  4. Reclaiming Connection: Decentralized Social Networks
  5. Web Economics & Discovery
  6. The Broken Discovery Machine
  7. Evolution of Web Links
  8. Code & Frameworks
  9. Breaking the Tech Debt Avoidance Loop
  10. Evolution of Scaling & High Availability
  11. Evolution of Configuration & Environment
  12. Evolution of API Support
  13. Evolution of Browser & Client Support
  14. Evolution of Deployment & DevOps
  15. Evolution of Real-time Capabilities
  16. The Visual Basic Gap in Web Development
  17. Evolution of Testing & Monitoring
  18. Evolution of Internationalization & Localization
  19. Evolution of Form Processing
  20. Evolution of Security
  21. Evolution of Caching
  22. Evolution of Data Management
  23. Evolution of Response Generation
  24. Evolution of Request Routing & Handling
  25. Evolution of Session & State Management
  26. Web Framework Responsibilities
  27. Evolution of Internet Clients
  28. Evolution of Web Deployment
  29. The Missing Architectural Layer in Web Development
  30. Development Velocity Gap: WordPress vs. Modern Frameworks
  31. Data & Storage
  32. Evolution of Web Data Storage
  33. Information Management
  34. Manual Bookkeeping with a Columnar Pad
  35. Managing Tasks Effectively: A Complete System
  36. Managing Appointments: Designing a Calendar System
  37. Building a Personal Knowledge Base
  38. Contact Management in the Digital Age
  39. Project Management for Individuals
  40. The Art of Response: Communicating with Purpose
  41. Strategic Deferral: Purposeful Postponement
  42. The Art of Delegation: Amplifying Impact
  43. Taking Action: Guide to Decisive Execution
  44. The Art of Deletion: Digital Decluttering
  45. Digital Filing: A Clutter-Free Life
  46. Managing Incoming Information
  47. Cloud & Infrastructure
  48. Moving from Cloud to Self-Hosted Infrastructure
  49. AWS Lightsail versus EC2
  50. WordPress on AWS Lightsail
  51. Migrating from Heroku to Dokku
  52. Storage & Media
  53. Vultr Object Storage on Django Wagtail
  54. Live Video Streaming with Nginx
  55. YI 4k Live Streaming
  56. Tools & Connectivity
  57. Multi Connection VPN
  58. Email Forms with AWS Lambda
  59. Static Sites with Hexo

Optimize Your Website!

Is your WordPress site running slowly? I offer a comprehensive service that includes needs assessments and performance optimizations. Get your site running at its best!

Check Out My Fiverr Gig!

Elsewhere

  1. YouTube
  2. Twitter
  3. GitHub