Skip to content

[FEATURE][AUTH]: Self-Service Password Reset Workflow (Forgot Password) #2542

@crivetimihai

Description

@crivetimihai

🔐 Feature: Self-Service Password Reset Workflow

Goal

Implement a self-service password reset workflow that enables users to securely recover account access without administrator intervention. This feature provides email-based password reset with time-limited tokens, security controls to prevent abuse, and comprehensive audit logging for compliance.

Why Now?

The current ContextForge authentication system lacks self-service password recovery:

  1. User Experience: Users who forget passwords must contact an administrator, causing delays and frustration
  2. Operational Burden: Administrators must manually reset passwords, consuming valuable time
  3. Security Best Practices: Modern authentication systems require self-service recovery with proper security controls
  4. Compliance Requirements: SOC2, ISO 27001, and enterprise policies require documented password recovery procedures
  5. Scalability: As user base grows, manual password resets become unsustainable
  6. 24/7 Availability: Users need password recovery outside business hours when admins may not be available

📖 User Stories

US-1: User - Request Password Reset

As a registered user
I want to request a password reset via email
So that I can recover access to my account without admin assistance

Acceptance Criteria:

Feature: Password Reset Request

  Scenario: Request password reset with valid email
    Given I am on the login page
    And I have forgotten my password
    When I click "Forgot Password?"
    And I enter my registered email "user@example.com"
    And I click "Send Reset Link"
    Then I should see "If this email is registered, you will receive a reset link"
    And a password reset email should be sent within 30 seconds
    And the reset token should expire in 1 hour
    And the event should be logged in auth_events

  Scenario: Request reset with unregistered email
    Given I enter an unregistered email "unknown@example.com"
    When I click "Send Reset Link"
    Then I should see the same message (no email enumeration)
    And no email should be sent
    And the attempt should be logged for security monitoring

  Scenario: Rate limiting on reset requests
    Given I have requested 5 password resets in 15 minutes
    When I request another reset
    Then I should see "Too many requests. Please try again later."
    And the request should be blocked for 15 minutes

Technical Requirements:

  • Constant-time response (prevent timing attacks)
  • No email enumeration (same response for valid/invalid emails)
  • Rate limiting: 5 requests per email per 15 minutes
  • Secure token generation (256-bit cryptographically random)
  • Token stored as hash (not plaintext)
US-2: User - Complete Password Reset

As a user who received a reset email
I want to set a new password using the reset link
So that I can regain access to my account

Acceptance Criteria:

Feature: Password Reset Completion

  Scenario: Reset password with valid token
    Given I received a password reset email
    And I click the reset link within 1 hour
    When I am redirected to the password reset page
    And I enter a new password meeting policy requirements
    And I confirm the new password
    And I click "Reset Password"
    Then my password should be updated
    And I should be redirected to login with success message
    And the reset token should be invalidated
    And all other sessions should be terminated (optional)
    And an email notification should be sent

  Scenario: Reset with expired token
    Given my reset token is older than 1 hour
    When I click the reset link
    Then I should see "This reset link has expired"
    And I should be offered to request a new link

  Scenario: Reset with already-used token
    Given I have already used my reset token
    When I click the link again
    Then I should see "This reset link has already been used"
    And I should be offered to request a new link

Technical Requirements:

  • One-time use tokens (invalidated after use)
  • Token expiration: 1 hour (configurable)
  • Password validation against policy
  • Previous password reuse check (if enabled)
  • Session termination on password change (configurable)
US-3: Security Team - Audit and Monitoring

As a security engineer
I want comprehensive logging of password reset activities
So that I can detect abuse and demonstrate compliance

Acceptance Criteria:

Feature: Password Reset Audit Trail

  Scenario: Log all reset activities
    Given password reset audit logging is enabled
    When any reset activity occurs
    Then the following should be logged:
      | Event Type              | Fields                                    |
      | RESET_REQUESTED         | email, ip_address, user_agent, timestamp  |
      | RESET_EMAIL_SENT        | email, token_hash, expires_at, timestamp  |
      | RESET_ATTEMPTED         | token_hash, ip_address, success, timestamp|
      | RESET_COMPLETED         | email, ip_address, timestamp              |
      | RESET_TOKEN_EXPIRED     | token_hash, timestamp                     |
      | RESET_RATE_LIMITED      | email, ip_address, timestamp              |

  Scenario: Alert on suspicious activity
    Given alert thresholds are configured
    When 10+ reset requests occur for same email in 1 hour
    Then an alert should be generated
    And the event should be flagged for review

Technical Requirements:

  • Structured JSON logging for SIEM integration
  • Prometheus metrics: password_reset_requests_total, password_reset_completions_total
  • Configurable alert thresholds
  • IP-based pattern detection
US-4: Platform Admin - Configure Reset Policy

As a platform administrator
I want to configure password reset policies
So that I can balance security and usability for my organization

Acceptance Criteria:

Feature: Password Reset Configuration

  Scenario: Configure reset token expiration
    Given I am configuring password reset settings
    When I set PASSWORD_RESET_TOKEN_EXPIRY_MINUTES=60
    Then reset tokens should expire after 60 minutes

  Scenario: Disable self-service reset
    Given my organization requires admin-only resets
    When I set PASSWORD_RESET_ENABLED=false
    Then the "Forgot Password?" link should not appear
    And the reset endpoint should return 403

  Scenario: Configure email settings
    Given I configure SMTP settings
    When a reset is requested
    Then the email should be sent via configured SMTP server
    And the email should use the configured template

Technical Requirements:

  • Environment variable configuration
  • Admin UI toggle for enabling/disabling
  • Customizable email templates
  • SMTP configuration (or SendGrid/SES integration)

🏗 Architecture

Password Reset Flow

┌─────────────────────────────────────────────────────────────────────────────┐
│                         PASSWORD RESET WORKFLOW                              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  User                    Gateway                    Email Service           │
│  ────                    ───────                    ─────────────           │
│    │                        │                            │                  │
│    │  1. Click "Forgot      │                            │                  │
│    │     Password"          │                            │                  │
│    │ ─────────────────────► │                            │                  │
│    │                        │                            │                  │
│    │  2. Enter email        │                            │                  │
│    │ ─────────────────────► │                            │                  │
│    │                        │                            │                  │
│    │                        │  3. Generate secure token  │                  │
│    │                        │     (256-bit random)       │                  │
│    │                        │                            │                  │
│    │                        │  4. Store token_hash +     │                  │
│    │                        │     expires_at in DB       │                  │
│    │                        │                            │                  │
│    │                        │  5. Send reset email ────► │                  │
│    │                        │                            │                  │
│    │  6. "Check your email" │                            │                  │
│    │ ◄───────────────────── │                            │                  │
│    │                        │                            │                  │
│    │  7. Click link in      │                            │                  │
│    │     email              │                            │                  │
│    │ ─────────────────────► │                            │                  │
│    │                        │                            │                  │
│    │                        │  8. Validate token:        │                  │
│    │                        │     - Not expired          │                  │
│    │                        │     - Not used             │                  │
│    │                        │     - Hash matches         │                  │
│    │                        │                            │                  │
│    │  9. Show password      │                            │                  │
│    │     form               │                            │                  │
│    │ ◄───────────────────── │                            │                  │
│    │                        │                            │                  │
│    │  10. Submit new        │                            │                  │
│    │      password          │                            │                  │
│    │ ─────────────────────► │                            │                  │
│    │                        │                            │                  │
│    │                        │  11. Validate password     │                  │
│    │                        │      against policy        │                  │
│    │                        │                            │                  │
│    │                        │  12. Hash with Argon2id    │                  │
│    │                        │                            │                  │
│    │                        │  13. Update user record    │                  │
│    │                        │                            │                  │
│    │                        │  14. Invalidate token      │                  │
│    │                        │                            │                  │
│    │                        │  15. Send confirmation ──► │                  │
│    │                        │      email                 │                  │
│    │                        │                            │                  │
│    │  16. Redirect to       │                            │                  │
│    │      login             │                            │                  │
│    │ ◄───────────────────── │                            │                  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Database Schema

-- Password reset tokens table
CREATE TABLE password_reset_tokens (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES email_users(id) ON DELETE CASCADE,
    token_hash VARCHAR(255) NOT NULL,  -- SHA-256 hash of token
    expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
    used_at TIMESTAMP WITH TIME ZONE,  -- NULL until used
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    ip_address VARCHAR(45),
    user_agent TEXT,
    
    INDEX idx_token_hash (token_hash),
    INDEX idx_user_id (user_id),
    INDEX idx_expires_at (expires_at)
);

-- Cleanup job: DELETE FROM password_reset_tokens WHERE expires_at < NOW() - INTERVAL '7 days';

📋 Implementation Tasks

Phase 1: Core Reset Flow

  • Create password_reset_tokens database table (Alembic migration)
  • Add PasswordResetService in mcpgateway/services/
  • Implement secure token generation (secrets.token_urlsafe)
  • Implement token storage (store hash, not plaintext)
  • Add POST /auth/email/forgot-password endpoint
  • Add GET /auth/email/reset-password/{token} endpoint (validate token)
  • Add POST /auth/email/reset-password/{token} endpoint (complete reset)
  • Add rate limiting (5 requests/15 min per email)

Phase 2: Email Integration

  • Create email template: password_reset_email.html
  • Add SMTP configuration to config.py
  • Implement EmailService for sending emails
  • Support SendGrid/AWS SES as alternatives
  • Add confirmation email after successful reset

Phase 3: Admin UI Integration

  • Add "Forgot Password?" link to login page
  • Create password reset request page
  • Create password reset form page
  • Add success/error message handling
  • Add Admin UI setting to enable/disable feature

Phase 4: Security & Audit

  • Implement constant-time token comparison
  • Add audit logging for all reset events
  • Add Prometheus metrics
  • Implement IP-based rate limiting
  • Add suspicious activity detection

Phase 5: Testing & Documentation

  • Unit tests for PasswordResetService
  • Integration tests for reset flow
  • Security tests (token enumeration, timing attacks)
  • Update user documentation
  • Add troubleshooting guide

⚙️ Configuration

# Password Reset Settings
PASSWORD_RESET_ENABLED=true                    # Enable self-service reset
PASSWORD_RESET_TOKEN_EXPIRY_MINUTES=60         # Token valid for 1 hour
PASSWORD_RESET_RATE_LIMIT=5                    # Max requests per window
PASSWORD_RESET_RATE_WINDOW_MINUTES=15          # Rate limit window
PASSWORD_RESET_INVALIDATE_SESSIONS=true        # Logout other sessions on reset

# Email Settings
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=noreply@example.com
SMTP_PASSWORD=secret
SMTP_FROM_EMAIL=noreply@example.com
SMTP_FROM_NAME="MCP Gateway"
SMTP_USE_TLS=true

✅ Success Criteria

  • Users can request password reset without admin intervention
  • Reset tokens expire after configured time (default: 1 hour)
  • Tokens are one-time use only
  • No email enumeration vulnerability
  • Rate limiting prevents abuse
  • All events logged for audit
  • Email delivery works reliably
  • Admin can enable/disable feature
  • Passes security review

🔗 Related Issues


📚 References

Metadata

Metadata

Assignees

Labels

COULDP3: Nice-to-have features with minimal impact if left out; included if time permitsdocumentationImprovements or additions to documentationenhancementNew feature or requestpythonPython / backend development (FastAPI)securityImproves security

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions