Repository navigation
Releases: dgates82/DGates.Identity.Jwt2Fa
Release list
v1.1.2
Dependency bump only — no API changes.
Changed
DGates.Identity.NotificationProvidersbumped to1.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.2v1.1.1
Dependency bump and a README restructure — no API changes.
Changed
DGates.Identity.NotificationProvidersbumped to1.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.mdanddocs/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.1v1.1.0
SonarQube Cloud static analysis and CI/tooling improvements — no API changes.
Added
- SonarQube Cloud static analysis wired into CI's
build-and-testjob viadotnet-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_dispatchruns weren't picking up the branch name (a SonarScanner limitation) — now
passed explicitly for any non-PR trigger.Register_WithWellFormedRequest_IsNotRejectedByValidationgets an explicit assertion (it
always failed correctly viaEnsureSuccessStatusCode(), 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 toAddAuthorizationBuilder,
and a clearer xUnit assertion form adopted. AuthCoreService's three near-identical email-sending call sites extracted into a shared
SendTemplatedEmailAsynchelper, 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.0v1.0.0
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.AdminOnlypolicy 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
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
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
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
ValidationProblemon invalid input (#12). sendtwofacodenow 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).forgotpasswordnow appends&isFirstLogin=trueto its reset link for an account that's never set its own password, matching the framingadmincreateuser's own first-login email already carries.registernow setsIAdminProvisionableUser.HasSetPasswordtotrueafter a successfulCreateAsync, matching whatresetpasswordalready does (#18).
Full diff: v1.0.0-beta.4...v1.0.0-beta.5
v1.0.0-beta.4
Fixed
EmailConfirmationPathnow supports an{email}token, substituted consistently onregister,sendemailconfirmation,admincreateuser, andadminupdateuser's email-change re-confirmation (#9).
Full diff: v1.0.0-beta.3...v1.0.0-beta.4
v1.0.0-beta.3
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
Added
unlockadmin endpoint — clears a locked-out user's lockout (LockoutEndset to now), matching what the source app'sAdmin/UserControlleralready did. Requires nothing beyondIdentityUser, 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