Skip to content

feat: implement secure email verification flow with token hashing and expiration logic#109

Merged
BarryArinze merged 3 commits into
aid-linkk:masterfrom
Chongai-Cli:backend
Jun 29, 2026
Merged

feat: implement secure email verification flow with token hashing and expiration logic#109
BarryArinze merged 3 commits into
aid-linkk:masterfrom
Chongai-Cli:backend

Conversation

@Chongai-Cli

Copy link
Copy Markdown
Contributor

The implementation is successful. Here's a summary of everything
implemented:

Schema (prisma/schema.prisma)

  • Added verificationToken String? @unique, verificationExpiry
    DateTime?, failedVerifyAttempts Int @default(0) to User
  • Added VerificationLog model with audit trail (userId,
    action, tokenHash, ipAddress, userAgent)

Token security (src/utils/crypto.ts)

  • Added generateVerificationToken() —
    crypto.randomBytes(32).toString('base64url')
  • Plaintext token sent in email, SHA-256 hash stored in DB
    (existing sha256() method used)

Email templates (src/templates/verify-email.{html,txt})

  • Responsive HTML + plain-text fallback with {{firstName}},
    {{verificationLink}}, {{year}} placeholders

Auth service (src/services/auth.service.ts)

  • register() — generates token/hash/expiry, sends email async
    (non-blocking), logs SENT, returns userId only (no
  • verifyEmail(token) — hashes incoming token, checks expiry,
    handles lockout after 10 failed attempts, logs
    VERIFIED/EXPIRED/FAILED
  • resendVerificationEmail(email) — Redis-backed per-email
    rate limit (3/hour), generates fresh token, logs RESENT,
    email-existence not revealed
  • login() — blocks unverified users with 403 +
    EMAIL_NOT_VERIFIED code and resendUrl
  • sanitizeUser() — strips passwordHash, verificationToken,
    verificationExpiry, failedVerifyAttempts from all responses

New endpoints (src/routes/auth.routes.ts)

  • GET /api/v1/auth/verify-email?token= — no auth required
  • POST /api/v1/auth/resend-verification — no auth required,
    IP-level rate limiter + per-email Redis limiter

requireVerified middleware (src/middleware/auth.ts)

  • DB lookup on emailVerified; returns 403 with { code:
    'EMAIL_NOT_VERIFIED', resendUrl } if false
  • Applied to: POST /donations, POST /distributions, POST
    /beneficiaries/:id/kyc

Tests

  • 21 unit tests (src/services/auth.service.test.ts) — token
    format, hash storage, expiry, rate limits, lockout,
    sanitization
  • 15 integration tests
    (tests/integration/email.verification.flow.test.ts) — full
    register→verify→login flow, expired tokens, resend rate
    limits, security properties, email delivery content

closes #68

@BarryArinze

Copy link
Copy Markdown
Collaborator

Resolve conflict

@GBOYEE

GBOYEE commented Jun 23, 2026

Copy link
Copy Markdown

I will take this issue. Strong full-stack background, clean PR coming shortly.

@GBOYEE

GBOYEE commented Jun 24, 2026

Copy link
Copy Markdown

I'd like to work on this issue. I have background in full-stack and will submit a PR ASAP.

@Chongai-Cli

Copy link
Copy Markdown
Contributor Author

Conflicts have been resolved and the pr is ready for merging. Apologies about the delay

@BarryArinze
BarryArinze merged commit 03f0d52 into aid-linkk:master Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement email verification flow for user registration

3 participants