Skip to content

Email verification on register #29

Description

@hateofhades

What

Send a verification email after registration. Gate reactions and comments (M5 features) behind email verification. Add POST /auth/verify-email and POST /auth/resend-verification endpoints.

Acceptance Criteria

  • email_verification_tokens table migration created
  • After POST /auth/register: sends verification email with 24-hour token
  • POST /api/v1/auth/verify-email accepts {"token": "..."} and sets email_verified_at
  • POST /api/v1/auth/resend-verification (protected, rate-limited) — resends verification email; invalidates old token
  • Attempting to access M5 features (reactions, comments) without verified email returns 403 {"error": "Please verify your email first", "code": "EMAIL_NOT_VERIFIED"}
  • email_verified_at column on users table (added in M1-001, nullable, set here)
  • cargo doc: public functions and types in this module have /// doc comments; cargo doc --no-deps produces no warnings for this module
  • Bruno collection: docs/bruno/auth/email-verification.bru added (or updated) with example request body and expected response shapes; uses {{base_url}} and {{access_token}} variables

Implementation Notes

-- migrations/000000000004_email_verification_tokens.sql
CREATE TABLE email_verification_tokens (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    token_hash TEXT UNIQUE NOT NULL,
    expires_at TIMESTAMPTZ NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

The verification gate in M5 handlers:

// In require_verified_email() helper:
if user.email_verified_at.is_none() {
    return Err(AppError::Forbidden("Please verify your email first"));
}

Rate limit POST /auth/resend-verification at 3 req/hour/user (not IP — logged-in endpoint).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions