Skip to content

Auth account lifecycle: password reset, email change, deactivation & audit trail — backend EPIC #77

Description

@grantfox-oss

DESCRIPTION

apps/api/src/auth/auth.service.ts only implements login and register — there is no way for a user who forgets their password to recover their account, no way to change the email on file, and no way for an admin to deactivate a compromised or fraudulent account. This epic closes the account-lifecycle gap using Supabase Auth's existing primitives, and logs every lifecycle event the same way the rest of the platform already does via AuditService.

GOAL

Users can recover a forgotten password and change their email through a real flow; admins can deactivate/reactivate an account; every auth lifecycle event (reset requested, reset completed, email changed, deactivated, reactivated) is audit-logged; and auth endpoints are rate-limited against abuse.

REQUIREMENTS

  • POST /auth/forgot-password — triggers Supabase's resetPasswordForEmail recovery flow (never reveal whether an email exists).
  • POST /auth/reset-password — completes the reset using the Supabase recovery token, sets the new password.
  • POST /auth/change-email (authenticated) — starts Supabase's email-change confirmation flow.
  • PATCH /users/:id/deactivate and PATCH /users/:id/reactivate (admin only, mirroring the admin-only pattern already used in UsersService.setRole) — soft-disable/enable an account (block login while deactivated).
  • Emit an audit event for every lifecycle action above via the existing AuditService.emit() pattern (see apps/api/src/audit/), the same way other modules already do.
  • Basic rate limiting on login, forgot-password, and register to prevent credential-stuffing/abuse (reuse @nestjs/throttler if already present, or add it scoped to these endpoints only).

ACCEPTANCE CRITERIA

  • Forgot/reset-password flow works end-to-end against a local Supabase instance (or mocked SupabaseService, per apps/api/src/**/*.service.spec.ts), including the "don't leak whether the email exists" behavior.
  • Deactivated users cannot log in; reactivation restores access; both are admin-only and audited.
  • Every new endpoint has a unit test mocking SupabaseService — no real VELAR database or credentials required.
  • npm run build, npm run lint, npm run test pass in apps/api with NO VELAR credentials.
  • docs/BACKEND.md updated with the new endpoints and the audit events they emit.

NOTES

Relevant files: apps/api/src/auth/auth.service.ts, apps/api/src/auth/auth.controller.ts, apps/api/src/users/users.service.ts, apps/api/src/users/users.controller.ts, apps/api/src/audit/audit.service.ts (reuse, don't reinvent), packages/types/src/ (add request/response types for the new endpoints). Do not touch supabase/migrations/ schema beyond what Supabase Auth already provides — no new tables required for this scope. EXTEND auth/users, don't rewrite existing login/register logic (docs/AGENTS.md §3).

No VELAR credentials required: verifiable locally with a mocked SupabaseService — no real database, passwords, or service_role key.

Difficulty: Advanced
Priority: High

PR REQUIREMENTS

  • Ship this as a single pull request — do not split into stacked/sequential PRs.
  • Your PR description must include Closes #<this-issue-number> (this issue's GitHub number) so merging auto-closes it.

CAMPAIGN REQUIREMENTS (FWC26)

To be eligible for the reward on this issue, the contributor must:

Metadata

Metadata

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26Third CampaignCampaign: Third Campaign

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions