Skip to content

Releases: dgates82/DGates.Identity.Jwt2Fa

v1.1.2

Choose a tag to compare

@dgates82 dgates82 released this 22 Sep 17:06
c75c0dd

Dependency bump only — no API changes.

Changed

  • DGates.Identity.NotificationProviders bumped to 1.1.1.

RC-verified before this release: tagged as a prerelease, pulled into
angular-dotnet-auth-template, full unit and Playwright e2e suites (chromium and
firefox) passed. Also deployed to the live demo and confirmed via real GCP Cloud
Logging that the underlying NotificationProviders 1.1.1 masking fix behaves
correctly in production — recipient email and phone both appear masked in real log
output from a live registration and SMS 2FA flow.

Install

dotnet add package DGates.Identity.Jwt2Fa --version 1.1.2

v1.1.1

Choose a tag to compare

@dgates82 dgates82 released this 21 Sep 13:14
4a238ee

Dependency bump and a README restructure — no API changes.

Changed

  • DGates.Identity.NotificationProviders bumped to 1.1.0.
  • README restructured — a live-demo callout, a grouped feature list, a concrete
    login/JWT example, and a package-ecosystem table; JWT/notification config detail,
    the full module/capability design, and email/SMS copy customization moved to
    docs/CONFIGURATION.md and docs/DESIGN.md.

RC-verified before this release: tagged as a prerelease, pulled into
angular-dotnet-auth-template, full unit and Playwright e2e suites (chromium and
firefox) passed.

Install

dotnet add package DGates.Identity.Jwt2Fa --version 1.1.1

v1.1.0

Choose a tag to compare

@dgates82 dgates82 released this 17 Sep 13:11
04cbb9d

SonarQube Cloud static analysis and CI/tooling improvements — no API changes.

Added

  • SonarQube Cloud static analysis wired into CI's build-and-test job via dotnet-sonarscanner,
    gated on the quality gate result — a failing gate now fails the build. Results are posted
    directly to the PR (status checks and a summary comment), and a quality gate badge was added
    to the README.
  • Test coverage reporting to SonarQube Cloud via dotnet test --collect:"XPlat Code Coverage"
    (coverlet.collector).

Fixed

  • workflow_dispatch runs weren't picking up the branch name (a SonarScanner limitation) — now
    passed explicitly for any non-PR trigger.
  • Register_WithWellFormedRequest_IsNotRejectedByValidation gets an explicit assertion (it
    always failed correctly via EnsureSuccessStatusCode(), Sonar just didn't recognize that as
    a formal assertion).
  • TwoFactorService.SendTwoFaCodeAsync's per-provider send logic extracted into
    TrySendTwoFaCodeAsync, bringing cyclomatic complexity under the SonarQube threshold —
    behavior-preserving, no logic change.
  • Cleared 25 of the 32 backlog SonarQube Cloud findings from issue #37: constant array literals
    in tests hoisted to shared static fields, magic numbers named as constants, duplicated string
    literals extracted to constants, a long doc-comment line wrapped, a test regex converted to
    [GeneratedRegex], authorization policy registration switched to AddAuthorizationBuilder,
    and a clearer xUnit assertion form adopted.
  • AuthCoreService's three near-identical email-sending call sites extracted into a shared
    SendTemplatedEmailAsync helper, clearing a duplication finding the constant-extraction above
    surfaced. Behavior-preserving only.

TUser on IAuthCoreService<TUser>/ITwoFactorService<TUser>/IUserActivationService<TUser>
was flagged as an unused type parameter by static analysis and reviewed — it's this package's
generic-user extension point, so it stays. 2 findings (constructor parameter count) remain open,
tracked in issue #37.

RC-verified before this release: tagged as a prerelease, pulled into
angular-dotnet-auth-template, full unit and Playwright e2e suites passed (including the three
flows touching the email-sending refactor).

Install

dotnet add package DGates.Identity.Jwt2Fa --version 1.1.0

v1.0.0

Choose a tag to compare

@dgates82 dgates82 released this 22 Aug 17:15
100d4b5

DGates.Identity.Jwt2Fa v1.0.0

Real, claims-bearing JWTs and multi-channel two-factor authentication (Authenticator/TOTP, Email, SMS) for ASP.NET Core Identity — generic over your own TUser.

Extracted from angular-dotnet-auth-template, where this logic previously lived directly in the template's controllers. This release generalizes it into a standalone package: two opt-in modules (AddAuthCore/MapAuthCore and Add2Fa/Map2Fa), four small capability interfaces so TUser only needs to implement what it uses, and a full admin user-management surface alongside auth — extracted together because both concerns shared the same TUser genericization problem in the source app.

Why this instead of MapIdentityApi<TUser>?

ASP.NET Core's built-in Identity API endpoints cover TOTP + recovery codes only (no SMS/email 2FA) and issue opaque, encrypted bearer tokens rather than real JWTs. This package fills both gaps for teams that want their own first-party JWT auth without adopting a full OAuth2/OIDC provider like Duende IdentityServer.

Highlights

  • Two opt-in modules, four capability interfaces — skip what you don't use, compile-error (not silent no-op) if you use one without its interface
  • Full admin user-management (list/get/create/update/unlock, activate/deactivate) gated by a Jwt2FaPolicies.AdminOnly policy built on JWT role claims — also usable directly on your own app's endpoints
  • Business logic lives in injectable services (Jwt2FaResult<T>), not endpoint delegates — every service is testable and usable outside this package's own minimal-API layer
  • Every email/SMS this package sends has an overridable subject/body — no fork required for different copy
  • Baseline safety net on every mapped endpoint: unhandled exceptions become a generic 500, invalid requests get a 400 ValidationProblem, with no setup required

Hardening

This release went through real integration testing against angular-dotnet-auth-template before publishing — several issues were found and fixed in the process, including a regressed authorization check on 2FA method switching (previously fixed once in the source app, dropped again during the port) and gaps in exception/validation handling that came from moving off MVC controllers. Full detail in CHANGELOG.md.

Requires

.NET 10. Bring your own IEmailSender/ISmsSender, or use DGates.Identity.NotificationProviders for both.

v1.0.0-beta.7

v1.0.0-beta.7 Pre-release
Pre-release

Choose a tag to compare

@dgates82 dgates82 released this 20 Aug 14:25
c832737

Fixed

ForgotPasswordEmailBody's default wording had a single <br/> between its first two lines while every other line break in it (and in the other five default templates) used <br/><br/> for paragraph spacing, so the opening line rendered as a cramped run-on against the paragraph beneath it (#30)

Full diff: v1.0.0-beta.6...v1.0.0-beta.7

v1.0.0-beta.6

v1.0.0-beta.6 Pre-release
Pre-release

Choose a tag to compare

@dgates82 dgates82 released this 20 Aug 11:49
0a6dc5f

Added

Every email/SMS this package sends now has a consumer-overridable subject/body on AuthCoreOptions — email confirmation, account setup/first-login, forgot password, and both 2FA code channels (Email/SMS) — each a plain {token}-substituted string defaulting to the package's existing wording, so a consumer wanting different copy no longer has to fork the package to get
it (#23)

Changed

Breaking: ResetPasswordRequestDto.Email is now UserId - resetpassword identifies the account by id, not email. ForgotPasswordPath gains a {userId} token (mirroring EmailConfirmationPath's existing one); EmailConfirmationPath's {email} token is removed, since its only purpose was pre-filling a reset-password form's email field, which no longer exists - the reset code is already cryptographically bound to a specific user, so a consuming reset/setup page never needs to display, collect, or transmit an email address at all (#26)

Fixed

forgotpassword now sends the same account-setup email admincreateuser sends when reissuing a first-login link (IAdminProvisionableUser.HasSetPassword == false), instead of its own "forgot your password" wording with just the link patched — the link's isFirstLogin=true correctly framed the destination page, but the email itself still told the recipient "we received a request to reset your password... if you did not request this, ignore it," which is backwards when an admin is reissuing the link on their behalf (#22)

Full diff: v1.0.0-beta.5...v1.0.0-beta.6

v1.0.0-beta.5

v1.0.0-beta.5 Pre-release
Pre-release

Choose a tag to compare

@dgates82 dgates82 released this 18 Aug 18:14
8914027

Fixed

  • Every mapped endpoint now has a baseline safety net: an unhandled exception is logged and turned into a generic 500 message instead of reaching the client, and request DTOs are validated with a 400 ValidationProblem on invalid input (#12).
  • sendtwofacode now sends Phone/SMS setup codes to the submitted phone number whenever the account isn't already verified for the Phone method specifically, instead of only when 2FA isn't enabled at all — switching from Email or Authenticator to Phone previously sent the code to the account's stored (empty) phone number and silently dropped it (#16).
  • forgotpassword now appends &isFirstLogin=true to its reset link for an account that's never set its own password, matching the framing admincreateuser's own first-login email already carries.
  • register now sets IAdminProvisionableUser.HasSetPassword to true after a successful CreateAsync, matching what resetpassword already does (#18).

Full diff: v1.0.0-beta.4...v1.0.0-beta.5

v1.0.0-beta.4

v1.0.0-beta.4 Pre-release
Pre-release

Choose a tag to compare

@dgates82 dgates82 released this 07 Aug 17:52
ce55327

Fixed

  • EmailConfirmationPath now supports an {email} token, substituted consistently on register, sendemailconfirmation, admincreateuser, and adminupdateuser's email-change re-confirmation (#9).

Full diff: v1.0.0-beta.3...v1.0.0-beta.4

v1.0.0-beta.3

v1.0.0-beta.3 Pre-release
Pre-release

Choose a tag to compare

@dgates82 dgates82 released this 07 Aug 16:58
519450a

Fixed

  • `login`, `login2fa`, and `getuserbyemail` now populate `IRoleAwareUser.Roles` before projecting the response, matching `getuserbyid`/`listusers`/`admincreateuser`. The JWT's role claim was always correct, but a consumer reading roles off the embedded `user` object (rather than decoding the JWT) previously saw an empty list on these three endpoints (#7).

Full diff: v1.0.0-beta.2...v1.0.0-beta.3

v1.0.0-beta.2

v1.0.0-beta.2 Pre-release
Pre-release

Choose a tag to compare

@dgates82 dgates82 released this 07 Aug 14:13
8b1d8bc

Added

  • unlock admin endpoint — clears a locked-out user's lockout (LockoutEnd set to now), matching what the source app's Admin/UserController already did. Requires nothing beyond IdentityUser, so it's part of core alongside the other admin endpoints (getuserbyid/listusers/admincreateuser/adminupdateuser/activate/deactivate).

Full diff: v1.0.0-beta.1...v1.0.0-beta.2