Skip to content

[Enhancement]: MfaService - TOTP & Backup Codes Management #243

Closed
1 of 1 issue completed
Closed

Description

@mathrmartins

Current source review — 2026-10-04

Commit: fc6c315 (develop). Result: Fail; full acceptance is not established.

TOTP enrollment/verification and backup generation/status APIs exist. The promised 12-character salted/versioned PBKDF2 codes and concurrent single-use enforcement are absent.

Requirement provenance: Original title/body and human discussion define the historical request. Additional engineering checks below are identified through current API contracts and repository invariants; they do not create or silently complete an original acceptance checklist.

Organization: Remain OPEN; the unresolved requirements below require acceptance or a product decision.

Open native sub-issues: #285.

Current implementation evidence

Requirement review

Requirement and provenance Source result Evidence Outstanding acceptance or defect
Manage TOTP enrollment and verification Partial apps/api/Source/Modules/GameGuild.Identity.Authentication/Services/TotpMfaService.cs:26-69; apps/api/Source/Modules/GameGuild.Identity.Authentication/Services/TotpMfaService.cs:82-163; apps/api/Source/Modules/GameGuild.Identity.Authentication/Controllers/MfaController.cs:47-95; apps/api/Source/Modules/GameGuild.Identity.Authentication/Data/Extensions/DependencyInjection.cs:119-131; apps/api/Source/Modules/GameGuild.Identity.Authentication/Commands/MfaMutationCommands.cs:11-31 Execute actor-bound setup/expiry/code/tolerance/lockout and persistence.
Manage single-use backup codes Fail apps/api/Source/Modules/GameGuild.Identity.Authentication/Services/BackupCodeMfaService.cs:23-66; apps/api/Source/Modules/GameGuild.Identity.Authentication/Services/BackupCodeMfaService.cs:110-144; apps/api/Source/Modules/GameGuild.Identity.Authentication/Repositories/UserMfaConfigurationRepository.cs:12-40; apps/api/Source/Modules/GameGuild.Identity.Authentication/Data/Configurations/UserMfaConfigurationConfiguration.cs:23-62; apps/api/Source/Modules/GameGuild.Identity.Authentication/Controllers/MfaController.cs:136-174 Protect concurrent code consumption and check count/status/regeneration at public boundary.
Recorded cryptographic backup-code hardening Fail apps/api/Source/Modules/GameGuild.Identity.Authentication/Services/BackupCodeMfaService.cs:183-199; apps/api/Source/Modules/GameGuild.SharedKernel/Configuration/ApplicationLayer/MfaOptions.cs:16-46 Implement/verify recorded length12 and salted/versioned PBKDF2 migration criteria or explicitly revise acceptance; source still SHA256/default8.

Remaining gaps

  • Backup hashing is unsalted SHA256 rather than promised PBKDF2-HMAC-SHA256 600k/versioned format.
  • Default length remains8 rather than recorded12.
  • Concurrent successful consumption has no atomic claim or EF concurrency token; failed-attempt increments are also read/modify/write.
  • Current TOTP enrollment, sequential/concurrent recovery use and lockout HTTP/storage execution absent.

This is static source inspection, including active wiring where observable. No product tests, builds, browser flows or production requests were executed in this review. Existing test definitions and historical result comments are not fresh execution evidence. Current findings supersede conflicting historical implementation assertions without deleting that history.

The original description, checklist status, title and labels are preserved. No functional criterion is marked complete by this audit.

Activity

  1. self-assigned this
    on Oct 3, 2025
  2. changed the title [-]💎 Feature Request[/-] [+][Enhancement]: MfaService - TOTP & Backup Codes Management[/+] on Oct 3, 2025
  3. mathrmartins commented on Sep 26, 2026

    @mathrmartins
    CollaboratorAuthor

    Resolution and acceptance criteria

    The issue had no description or checklist, so I used the title as its acceptance scope: TOTP enrollment/verification and MFA backup-code management.

    Implemented on the local feature/issue-closeout worktree:

    • TOTP secrets use a cryptographic RNG for 160-bit Base32 values, remain encrypted at rest, and are checked against the current 30-second step with a one-step tolerance and constant-time comparison.
    • Ten 12-character backup codes are generated with a cryptographic RNG. New stored values use salted, versioned PBKDF2-HMAC-SHA256 (600,000 iterations); old SHA-256 values remain verifiable during migration.
    • Backup-code verification consumes a value once, including protection against concurrent consumption. Five failed TOTP or backup-code attempts set a 15-minute lockout.
    • Existing authenticated status and regenerate endpoints continue to return status only and reveal codes only when generated.

    Evidence: BackupCodeMfaService.cs, TotpMfaService.cs, UserMfaConfigurationConfiguration.cs, BackupCodeMfaServiceSecurityTests.cs, TotpMfaServiceSecurityTests.cs, and EfConfigAndExtendedTests.UserMfaConfigurationConfiguration_ConfiguresEntity.

    Verification passed on 2026-09-26: dotnet test apps/api/tests/GameGuild.Identity.Authentication.UnitTests/GameGuild.Identity.Authentication.UnitTests.csproj --no-restore — 1,757 passed, 0 failed.

    The work is in the local feature branch; no PR has been opened yet. Reopen with concrete additional criteria if this title was intended to include MFA methods beyond TOTP and recovery codes.

  4. mathrmartins commented on Oct 5, 2026

    @mathrmartins
    CollaboratorAuthor

    Implementation increment is now PR #686, head 38c81a5a75ed6202235f6bb047af662683a49690. This issue remains OPEN while the remaining acceptance is verified.

    The change restores the previously recorded 12-character/PBKDF2/600,000-iteration criteria, legacy compatibility, single use under concurrent/stale contexts and five-failure/15-minute lockout. Pending enrollment cannot use backup codes. New TOTP enrollments have a fixed deadline; successful confirmation records completion.

    The previously reproduced status gap is fixed without breaking numeric v1 fields. Newly issued sets retain original totals across consumption/configuration changes. Legacy fields are lower bounds with areUsageCountsKnown=false; original issuance remains unknown. No fabricated historical used count is claimed.

    Current local evidence: 2,083 authentication, 1,667 authorization, 1,371 SharedKernel, 106 selected API architecture/security/bearer, nine actual migrated PostgreSQL/HTTP recovery and three client contract executions pass. There are 35 new cases. Configured Release solution build exits 0 with zero warnings/errors; EF reports no pending model changes; typed client generation/typecheck/diff pass. All 1,296 OpenAPI paths stay unchanged; only two response schemas change. Committed evidence and limitations.

    The baseline reproduced four unit defects and double consumption in real PostgreSQL. Superseded/interrupted attempts and the invalid expectation that a null token field should be absent are retained and excluded. HTTP recovery uses a test principal; real bearer validation is a separate test selection. Existing anonymous MFA verification does not issue access/refresh tokens and its complete sign-in challenge flow is not certified here.

    Exact-head GitHub gates and develop merge are pending. Configured external email delivery for #223 and real authenticator QR acceptance for #285 remain unverified; #243 retains its native child. This increment does not close these issues or certify production delivery.

  5. mathrmartins commented on Oct 5, 2026

    @mathrmartins
    CollaboratorAuthor

    MFA recovery increment merged — original issue remains OPEN

    PR #686 is MERGED into develop at 8e1266698a0998364ab39a34078e0fd16eaa17c8 (2026-10-05T03:31:03Z). Accepted head: 10e1df87c50d4f6a8280b42b6ffcdfff450b2429.

    All applicable matching-head checks passed: API, Web, clean migration/model compatibility, OpenAPI/client consistency, repository policy, tracked-artifact checks, PR Required Gate, Codacy and four CodeQL analyses. CI run executed 151 API integration, 1,049 API unit, 2,083 authentication and 1,371 SharedKernel cases, all passing (4,654 principal executions), followed by 14 passing repeated OpenAPI HTTP cases. Both Release builds had zero warnings/errors. Nonapplicable Testing Lab/Economy/Emception jobs were skipped.

    Local evidence remains 5,239 distinct cases, including 35 new cases, with the full warning/error-clean solution build, real migrated PostgreSQL concurrency/replay/actor/lockout checks, legacy compatibility and regenerated client contracts. Repeated, superseded, interrupted and crashed attempts are excluded; the previous head's 20-minute API cancellation is retained as failure history. The API allowance was extended to 30 minutes without dropping a test or gate.

    Implementation and boundary map: full original issuance counts for new sets, explicit unknown legacy history, 12-character/600,000-iteration backup criteria, guarded concurrent single use, pending-enrollment rejection and fixed new-enrollment deadline/completion state.

    #223, #243 and #285 remain OPEN. Configured external recovery-email delivery and a real authenticator QR round trip remain unverified. #243 retains its native child. Existing anonymous MFA verification returns no access/refresh tokens; complete sign-in challenge/session acceptance is not certified by this increment. No automatic closure or production-delivery claim is made.

    The primary develop checkout is synchronized with all 55 unrelated local files preserved byte-for-byte and by status. The integrated branch was removed locally/remotely. Two checkouts are reused and no stashes remain; password hashing/policy work under #254/#255 continues in the isolated checkout.

  6. mathrmartins commented on Oct 11, 2026

    @mathrmartins
    CollaboratorAuthor

    Verification at current develop (2026-10-11, ecfc427) — all three gaps from the 2026-10-04 review are now closed. Closing with evidence.

    1. Recorded cryptographic backup-code hardening — implemented.

    • BackupCodeMfaService.HashBackupCodeAsync now derives salted, versioned PBKDF2-HMAC-SHA256 at 600,000 iterations (16-byte salt, 32-byte hash, pbkdf2-sha256$600000$… format): apps/api/Source/Modules/GameGuild.Identity.Authentication/Services/BackupCodeMfaService.cs:205-213. Legacy unsalted SHA256 rows remain verifiable exactly once via fixed-time comparison (BackupCodeMfaService.cs:226-243).
    • MfaOptions.BackupCodeLength default is now 12: apps/api/Source/Modules/GameGuild.SharedKernel/Configuration/ApplicationLayer/MfaOptions.cs:34.
    • Tests: BackupCodeRecoverySecurityTests.NewHashesAreSaltedVersionedPbkdf2 / DefaultCodesHonorRecordedTwelveCharacterCriterion / LegacySha256CodeRemainsUsableExactlyOnce / MalformedOrDowngradedHashesFailClosed (apps/api/tests/GameGuild.Identity.Authentication.UnitTests/Services/BackupCodeRecoverySecurityTests.cs:14-121).

    2. Concurrent single-use enforcement — implemented.

    • EF concurrency tokens on every security-relevant column of the MFA configuration (is_enabled, totp_secret_key, backup_codes, failed_attempts, locked_out_until, is_setup_complete, setup_expires_at): apps/api/Source/Modules/GameGuild.Identity.Authentication/Data/Configurations/UserMfaConfigurationConfiguration.cs:26-55, unique user index :64.
    • Consumption retries up to 16 times on DbUpdateConcurrencyException with repository-side reload: BackupCodeMfaService.cs:94-96 and :151-155; UserMfaConfigurationRepository.cs:42-47.
    • Real PostgreSQL proof: MfaRecoveryPostgreSqlTests.TwoIndependentContextsCannotBothConsumeSameCode and SimultaneousVerificationReturnsExactlyOneCommittedSuccess (apps/api/tests/GameGuild.API.IntegrationTests/MfaRecoveryPostgreSqlTests.cs:24-85), plus FiveFailuresFromStaleContextsAccumulateAndBlockCorrectCode, StaleVerifierCannotAcceptCodeAfterRegeneration.

    3. TOTP enrollment/verification execution — implemented and tested.

    • TotpRecoverySecurityTests.SetupEncryptsRandomSecretAndConfirmationCompletesEnrollment / IndependentAuthenticatorCodesFollowRecordedThirtySecondWindow / ExpiredPendingSetupClearsSecretAndRecoveryCodes (apps/api/tests/GameGuild.Identity.Authentication.UnitTests/Services/TotpRecoverySecurityTests.cs:14-86).
    • HTTP-level enrollment/completion binding and recovery journeys: MfaSignInEnrollmentPostgreSqlTests.cs, MfaSignInCompletionPostgreSqlTests.cs, MfaRecoveryPostgreSqlTests.cs, MfaEnrollmentBindingMigrationPostgreSqlTests.cs (apps/api/tests/GameGuild.API.IntegrationTests/).

    TOTP/backup-code scope of this issue (and landed sub-issue #285) is verified complete at develop. Broader MFA-system scope (SMS, method management UI, metrics, docs) remains tracked by #244.

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

Metadata

Metadata

Assignees

Labels

authenticationIssues related to authentication moduleback-endTask for back-end developers

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions