@ambushsoftworks/nestjs-auth-graphql 0.17.0-rc.2 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -27,6 +27,67 @@ for buried obligations. **The marker was introduced in 0.9.0 and has not been
27
27
  retro-applied**, so it is reliable from 0.9.0 onward only. Convention adopted
28
28
  from `@ambushsoftworks/nestjs-payments-graphql`.
29
29
 
30
+ ## [0.17.0] - 2026-10-02
31
+
32
+ Passwordless sign-up with a passkey, a step-up token on sign-in, and fixes for
33
+ **account enumeration in password reset and email verification** (present in
34
+ every earlier version). Identical to `0.17.0-rc.2`, which LiftIQ piloted on
35
+ staging and an Android device. This entry is the summary for anyone coming from
36
+ 0.16.x; the two release-candidate entries below have the detail.
37
+
38
+ ### ⚠ Security
39
+
40
+ - **Password reset and email verification revealed which addresses have
41
+ accounts**: through a lock or social-only error, a cooldown only real accounts
42
+ had, account checks before the code, a password-strength error, response
43
+ timing, and "already verified". Every signed-out, email-keyed flow now answers
44
+ alike for every address. **If you are on 0.16.x or earlier, upgrade.**
45
+
46
+ ### ⚠ External configuration required
47
+
48
+ Only for passwordless sign-up:
49
+ - `PasskeyChallenge.userId` must not be a foreign key to users
50
+ (`assertPasskeyRepositoryContract` checks it).
51
+ - `IUserRepository.create` must store the `emailVerified` it is given, and
52
+ `IUserRepository.delete` must work.
53
+ - The email service needs `sendSignupCodeEmail` (`ConfigurableEmailService` has
54
+ it with the default renderer).
55
+
56
+ ### Added
57
+
58
+ - **Passwordless sign-up**: `performStartPasskeySignup` →
59
+ `performVerifyPasskeySignupCode` (returns a verified `signupId`) →
60
+ `performCompletePasskeySignup`, plus `performPasskeySignupOptions` to retry
61
+ the passkey step without the code. The account exists only once its passkey
62
+ does.
63
+ - **`stepUp.issueOnLogin`**: fresh sign-ins return a step-up token, so an app can
64
+ offer "Create a passkey?" without a second proof. Never from a refresh or the
65
+ biometric login.
66
+ - **`retryAfterSeconds` on every `RATE_LIMIT_EXCEEDED`.**
67
+ - New codes: `PASSWORD_RESET_CODE_INVALID`, `EMAIL_VERIFICATION_CODE_INVALID`,
68
+ the `PASSKEY_SIGNUP_*` family; `VERIFICATION_CODE_*` now used for signed-in
69
+ code checks.
70
+
71
+ ### Changed — breaking
72
+
73
+ - **Code failures are no longer `UNAUTHENTICATED`.** Password reset and
74
+ verify-email each report one code for every failure (no remaining-attempts
75
+ count); verify-phone and step-up by email report `VERIFICATION_CODE_INVALID` /
76
+ `_EXPIRED` / `_EXHAUSTED`. Update any client logic that matched
77
+ `UNAUTHENTICATED` or the old messages.
78
+ - `requestPasswordReset` no longer throws for a locked account, and its cooldown
79
+ applies to every address. `verifyEmail` refuses an already verified address.
80
+ `resendVerificationEmail` answers alike for every address.
81
+ - A misconfigured per-realm `verification.baseUrl` is logged through
82
+ `IAuthLogger.error` instead of failing the request.
83
+ - `PasskeyChallengePurpose` includes `'signup'`; `StepUpMethod` includes
84
+ `'oauth'`; `AuthRateLimitException` requires `retryAfterSeconds`.
85
+
86
+ ### Upgrading from an RC
87
+
88
+ From rc.1: read the rc.2 entry (codes changed, and step 3 of sign-up needs the
89
+ verified `signupId`). From rc.2: nothing changes.
90
+
30
91
  ## [0.17.0-rc.2] - 2026-10-02
31
92
 
32
93
  Fixes from LiftIQ's pilot of rc.1, chiefly **account enumeration in password
package/README.md CHANGED
@@ -1401,6 +1401,14 @@ renderer); otherwise `PASSKEY_SIGNUP_UNAVAILABLE`.
1401
1401
  | `PASSKEY_SIGNUP_VERIFICATION_FAILED` | 400 | The created passkey did not verify |
1402
1402
  | `PASSKEY_SIGNUP_UNAVAILABLE` | 503 | No passkeys, or no `sendSignupCodeEmail` |
1403
1403
 
1404
+ **An expired challenge can leave an orphaned passkey.** If the options expire
1405
+ (`passkey.registrationTimeoutSeconds`, 300 s by default) while the device's
1406
+ passkey sheet is still open, the platform may already have saved the passkey
1407
+ when the app gets `PASSKEY_SIGNUP_CHALLENGE_EXPIRED`. The retry then creates a
1408
+ second one, and the first stays in the user's password manager with no account
1409
+ behind it. Neither side can prevent this; it is rare at the default timeout.
1410
+ Reported by LiftIQ on Android.
1411
+
1404
1412
  **What your repositories must do for it:**
1405
1413
  - `IUserRepository.create` must store the `emailVerified` it is given (the
1406
1414
  OAuth sign-up already relies on this).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ambushsoftworks/nestjs-auth-graphql",
3
- "version": "0.17.0-rc.2",
3
+ "version": "0.17.0",
4
4
  "description": "Production-grade authentication package for NestJS with GraphQL, supporting JWT, OAuth, email/SMS verification, and biometric auth",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",