@ambushsoftworks/nestjs-auth-graphql 0.15.1 → 0.16.0-rc.1

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.
Files changed (100) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/README.md +311 -3
  3. package/dist/auth.module.d.ts +17 -0
  4. package/dist/auth.module.d.ts.map +1 -1
  5. package/dist/auth.module.js +91 -0
  6. package/dist/auth.module.js.map +1 -1
  7. package/dist/constants.d.ts +2 -0
  8. package/dist/constants.d.ts.map +1 -1
  9. package/dist/constants.js +3 -1
  10. package/dist/constants.js.map +1 -1
  11. package/dist/dto/passkey.dto.d.ts +43 -0
  12. package/dist/dto/passkey.dto.d.ts.map +1 -0
  13. package/dist/dto/passkey.dto.js +5 -0
  14. package/dist/dto/passkey.dto.js.map +1 -0
  15. package/dist/enums/verification-type.enum.d.ts +3 -2
  16. package/dist/enums/verification-type.enum.d.ts.map +1 -1
  17. package/dist/enums/verification-type.enum.js +1 -0
  18. package/dist/enums/verification-type.enum.js.map +1 -1
  19. package/dist/exceptions/step-up.exceptions.d.ts +11 -0
  20. package/dist/exceptions/step-up.exceptions.d.ts.map +1 -0
  21. package/dist/exceptions/step-up.exceptions.js +33 -0
  22. package/dist/exceptions/step-up.exceptions.js.map +1 -0
  23. package/dist/index.d.ts +9 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +8 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/interfaces/auth-lifecycle-hooks.interface.d.ts +2 -0
  28. package/dist/interfaces/auth-lifecycle-hooks.interface.d.ts.map +1 -1
  29. package/dist/interfaces/auth-logger.interface.d.ts +10 -1
  30. package/dist/interfaces/auth-logger.interface.d.ts.map +1 -1
  31. package/dist/interfaces/auth-logger.interface.js +9 -0
  32. package/dist/interfaces/auth-logger.interface.js.map +1 -1
  33. package/dist/interfaces/biometric-verifier.interface.d.ts.map +1 -1
  34. package/dist/interfaces/email-service.interface.d.ts +1 -0
  35. package/dist/interfaces/email-service.interface.d.ts.map +1 -1
  36. package/dist/interfaces/email-template-renderer.interface.d.ts +5 -0
  37. package/dist/interfaces/email-template-renderer.interface.d.ts.map +1 -1
  38. package/dist/interfaces/index.d.ts +1 -0
  39. package/dist/interfaces/index.d.ts.map +1 -1
  40. package/dist/interfaces/index.js +1 -0
  41. package/dist/interfaces/index.js.map +1 -1
  42. package/dist/interfaces/passkey-repository.interface.d.ts +48 -0
  43. package/dist/interfaces/passkey-repository.interface.d.ts.map +1 -0
  44. package/dist/interfaces/passkey-repository.interface.js +13 -0
  45. package/dist/interfaces/passkey-repository.interface.js.map +1 -0
  46. package/dist/passkey/passkey-json.types.d.ts +44 -0
  47. package/dist/passkey/passkey-json.types.d.ts.map +1 -0
  48. package/dist/passkey/passkey-json.types.js +3 -0
  49. package/dist/passkey/passkey-json.types.js.map +1 -0
  50. package/dist/passkey/webauthn-adapter.d.ts +104 -0
  51. package/dist/passkey/webauthn-adapter.d.ts.map +1 -0
  52. package/dist/passkey/webauthn-adapter.js +207 -0
  53. package/dist/passkey/webauthn-adapter.js.map +1 -0
  54. package/dist/repositories/in-memory-passkey.repository.d.ts +21 -0
  55. package/dist/repositories/in-memory-passkey.repository.d.ts.map +1 -0
  56. package/dist/repositories/in-memory-passkey.repository.js +72 -0
  57. package/dist/repositories/in-memory-passkey.repository.js.map +1 -0
  58. package/dist/resolvers/base-auth.resolver.d.ts +20 -0
  59. package/dist/resolvers/base-auth.resolver.d.ts.map +1 -1
  60. package/dist/resolvers/base-auth.resolver.js +103 -0
  61. package/dist/resolvers/base-auth.resolver.js.map +1 -1
  62. package/dist/services/auth.service.d.ts +5 -0
  63. package/dist/services/auth.service.d.ts.map +1 -1
  64. package/dist/services/auth.service.js +24 -0
  65. package/dist/services/auth.service.js.map +1 -1
  66. package/dist/services/biometric-challenge.service.d.ts.map +1 -1
  67. package/dist/services/biometric-challenge.service.js.map +1 -1
  68. package/dist/services/configurable-email.service.d.ts +1 -0
  69. package/dist/services/configurable-email.service.d.ts.map +1 -1
  70. package/dist/services/configurable-email.service.js +18 -0
  71. package/dist/services/configurable-email.service.js.map +1 -1
  72. package/dist/services/default-email-template-renderer.d.ts +5 -0
  73. package/dist/services/default-email-template-renderer.d.ts.map +1 -1
  74. package/dist/services/default-email-template-renderer.js +31 -0
  75. package/dist/services/default-email-template-renderer.js.map +1 -1
  76. package/dist/services/passkey.service.d.ts +101 -0
  77. package/dist/services/passkey.service.d.ts.map +1 -0
  78. package/dist/services/passkey.service.js +498 -0
  79. package/dist/services/passkey.service.js.map +1 -0
  80. package/dist/services/step-up-token.service.d.ts +15 -0
  81. package/dist/services/step-up-token.service.d.ts.map +1 -0
  82. package/dist/services/step-up-token.service.js +71 -0
  83. package/dist/services/step-up-token.service.js.map +1 -0
  84. package/dist/services/step-up.service.d.ts +50 -0
  85. package/dist/services/step-up.service.d.ts.map +1 -0
  86. package/dist/services/step-up.service.js +142 -0
  87. package/dist/services/step-up.service.js.map +1 -0
  88. package/dist/services/verification.service.d.ts +2 -2
  89. package/dist/services/verification.service.d.ts.map +1 -1
  90. package/dist/services/verification.service.js +5 -4
  91. package/dist/services/verification.service.js.map +1 -1
  92. package/dist/test-utils/software-authenticator.d.ts +37 -0
  93. package/dist/test-utils/software-authenticator.d.ts.map +1 -0
  94. package/dist/test-utils/software-authenticator.js +212 -0
  95. package/dist/test-utils/software-authenticator.js.map +1 -0
  96. package/dist/utils/passkey-rp.d.ts +13 -0
  97. package/dist/utils/passkey-rp.d.ts.map +1 -0
  98. package/dist/utils/passkey-rp.js +89 -0
  99. package/dist/utils/passkey-rp.js.map +1 -0
  100. package/package.json +6 -1
package/CHANGELOG.md CHANGED
@@ -27,6 +27,107 @@ 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.16.0-rc.1] - 2026-10-01
31
+
32
+ Passkeys (WebAuthn), and step-up re-authentication to protect adding one.
33
+
34
+ **Release candidate**, published to the `next` dist-tag for a pilot on real
35
+ devices; `latest` stays on 0.15.x. Install with
36
+ `npm install @ambushsoftworks/nestjs-auth-graphql@next`.
37
+
38
+ ### ⚠ External configuration required
39
+
40
+ Only if you enable passkeys. None of these is visible to a compiler or a test
41
+ suite; each fails as an opaque error on the device. Details in the README,
42
+ "Passkeys → Platform setup".
43
+
44
+ - **Install the optional peer** `@simplewebauthn/server@^14`. It needs
45
+ **Node.js 20+**; the package itself still supports 18 without passkeys. Boot
46
+ fails with the install command if it is missing.
47
+ - **Web:** serve the frontend over HTTPS on `passkey.rp.id` or a subdomain of it,
48
+ and list its exact origin in `passkey.rp.origins`.
49
+ - **Android:** publish `https://<rp.id>/.well-known/assetlinks.json` with
50
+ `delegate_permission/common.get_login_creds` for the app, and add
51
+ `android:apk-key-hash:<base64url SHA-256 of the signing certificate>` to
52
+ `passkey.rp.origins`. With Play App Signing, that is Google's app signing key.
53
+ - **iOS:** publish `https://<rp.id>/.well-known/apple-app-site-association` with
54
+ the app under `webcredentials.apps`, and add `webcredentials:<rp.id>` to the
55
+ app's Associated Domains entitlement.
56
+ - **Database:** tables for passkey credentials and challenges (reference Prisma
57
+ schema in the README), and, if your verification repository stores the type
58
+ in a database enum, the new value `step-up`.
59
+
60
+ ### Added
61
+
62
+ - **Passkeys.** `PasskeyService` and `IPasskeyRepository`, enabled by
63
+ `passkeyRepositoryInstance` and `passkey.rp`:
64
+ ```
65
+ registrationOptions(userId, { stepUpToken }) -> { challengeId, options }
66
+ verifyRegistration(userId, { challengeId, responseJson, name? })
67
+ authenticationOptions() -> { challengeId, options } // no username
68
+ verifyAuthentication({ challengeId, responseJson }) -> session
69
+ listPasskeys / renamePasskey / removePasskey
70
+ ```
71
+ Discoverable credentials (usernameless sign-in, browser autofill),
72
+ `userVerification` configurable and `'required'` by default, EdDSA / ES256 /
73
+ RS256. Sessions come from `issueAuthSession`, so account status, cookie auth,
74
+ realm claims and `SESSION_ISSUED` apply unchanged. Verification is by
75
+ `@simplewebauthn/server`, loaded only when passkeys are configured and kept
76
+ out of the published type declarations.
77
+ - **What the package enforces on top of the library:** single-use challenges
78
+ bound to purpose, user and realm and consumed before anything is checked; the
79
+ realm on the stored credential; the `userHandle` (the library does not check
80
+ it); the signature counter, with a compare-and-set and a
81
+ `PASSKEY_COUNTER_REGRESSION` event; global uniqueness of credential ids
82
+ (`PasskeyCredentialExistsError`); refusing to remove an account's last way in.
83
+ - **Step-up re-authentication.** `StepUpService` and `StepUpTokenService`: a
84
+ signed-in user re-authenticates with a password, a passkey or an emailed
85
+ 6-digit code and receives a five-minute token bound to user and realm.
86
+ **Adding a passkey requires one**: a passkey survives a password change and
87
+ logout-all, so a stolen session must not be able to add one. Wrong passwords
88
+ count toward brute-force lockout. The token is signed with an HKDF-derived
89
+ key, so it never passes as an access token.
90
+ - `BaseAuthResolver` methods: `performGetStepUpMethods`,
91
+ `performRequestStepUpEmailCode`, `performStepUpPasskeyOptions`,
92
+ `performReauthenticate`, `performPasskeyRegistrationOptions`,
93
+ `performVerifyPasskeyRegistration`, `performPasskeyAuthenticationOptions`,
94
+ `performVerifyPasskeyAuthentication`, `performListPasskeys`,
95
+ `performRenamePasskey`, `performRemovePasskey`. WebAuthn JSON crosses GraphQL
96
+ as a `String`.
97
+ - Options `passkey` (`rp`, `userVerification`, timeouts, `rateLimit`,
98
+ `userDisplayName`) and `stepUp.ttlSeconds`, validated at boot.
99
+ - Lifecycle hooks `onPasskeyRegistered` and `onPasskeyRemoved`, not awaited.
100
+ Wire the first to a notification email.
101
+ - Security events `PASSKEY_REGISTERED`, `PASSKEY_REGISTRATION_FAILURE`,
102
+ `PASSKEY_LOGIN_SUCCESS`, `PASSKEY_LOGIN_FAILURE`, `PASSKEY_COUNTER_REGRESSION`,
103
+ `PASSKEY_RENAMED`, `PASSKEY_REMOVED`, `STEP_UP_SUCCESS`, `STEP_UP_FAILURE`.
104
+ - Exceptions `StepUpRequiredException` (`STEP_UP_REQUIRED`),
105
+ `StepUpUnavailableException` (`STEP_UP_UNAVAILABLE`), `AuthRateLimitException`
106
+ (`RATE_LIMIT_EXCEEDED`), as `GraphQLError`s so the code reaches clients.
107
+ - `IEmailService.sendStepUpCodeEmail` and
108
+ `IEmailTemplateRenderer.renderStepUpCodeEmail`, both optional; implemented by
109
+ `ConfigurableEmailService` and `DefaultEmailTemplateRenderer`.
110
+ - `VerificationType.STEP_UP`, and `generateCodeForUserId` /
111
+ `validateCodeForUserId` accept `'step-up'`.
112
+ - `AuthService.requireActiveUser` and `AuthService.verifyPasswordForStepUp`.
113
+ - `InMemoryPasskeyRepository`, for tests and a single instance.
114
+
115
+ ### Changed
116
+
117
+ - `RepositoryVerificationType` includes `VerificationType.STEP_UP`. An adapter
118
+ with an exhaustive `switch` over it needs the new case.
119
+ - `BaseAuthResolver` gains the protected properties `authPasskeys` and
120
+ `authStepUp`, injected by property so its constructor is unchanged. A
121
+ subclass that declares members with those names must rename them.
122
+
123
+ ### Fixed
124
+
125
+ - The 0.14.0 notes and code comments said WebAuthn could be added as a second
126
+ `IBiometricVerifier` "without reshaping the port". It could not: a passkey
127
+ needs authenticator data and a user handle, a counter write, a registration
128
+ ceremony and challenges issued before any credential is known. Passkeys have
129
+ their own port, and the comments now say so.
130
+
30
131
  ## [0.15.1] - 2026-10-01
31
132
 
32
133
  ### Fixed
package/README.md CHANGED
@@ -19,6 +19,8 @@ Production-grade authentication module for NestJS GraphQL + REST APIs. JWT, cook
19
19
  - [Phone \& SMS Verification](#phone--sms-verification)
20
20
  - [OAuth](#oauth)
21
21
  - [Biometric Authentication](#biometric-authentication)
22
+ - [Passkeys](#passkeys)
23
+ - [Step-Up Re-authentication](#step-up-re-authentication)
22
24
  - [Brute Force Protection](#brute-force-protection)
23
25
  - [Password Reset](#password-reset)
24
26
  - [Password Policy](#password-policy)
@@ -38,6 +40,8 @@ Production-grade authentication module for NestJS GraphQL + REST APIs. JWT, cook
38
40
  - [Composable Email](#composable-email-email)
39
41
  - [Verification Options](#verification-options-verification)
40
42
  - [Biometric Options (`biometric`)](#biometric-options-biometric)
43
+ - [Passkey Options (`passkey`)](#passkey-options-passkey)
44
+ - [Step-Up Options (`stepUp`)](#step-up-options-stepup)
41
45
  - [SendGrid Options (`sendgrid`)](#sendgrid-options-sendgrid)
42
46
  - [Twilio Options (`twilio`)](#twilio-options-twilio)
43
47
  - [Optional Instance Options](#optional-instance-options)
@@ -79,6 +83,8 @@ npm install @nestjs/common @nestjs/core @nestjs/graphql @nestjs/jwt @nestjs/pass
79
83
 
80
84
  `resend` is an optional peer dependency -- install it only if using the Resend email sender.
81
85
 
86
+ `@simplewebauthn/server` (^14, Node.js 20+) is an optional peer dependency -- install it only if using [passkeys](#passkeys). Boot fails with the install command if passkeys are configured without it.
87
+
82
88
  Supports NestJS 10 and NestJS 11. CI runs the unit and end-to-end suites on both: NestJS 10 with `@nestjs/graphql` 12, Express 4 and Apollo Server 4, and NestJS 11 with `@nestjs/graphql` 13, Express 5 and Apollo Server 5.
83
89
 
84
90
  ## Quick Start
@@ -266,6 +272,22 @@ When cookie auth is enabled, pass the GraphQL `context` so tokens are set as Htt
266
272
  | `performResetPassword(input, context?)` | Reset password |
267
273
  | `performChangePassword(userId, current, new)` | Change password |
268
274
 
275
+ **Passkeys and step-up** (see [Passkeys](#passkeys)):
276
+
277
+ | Method | Purpose |
278
+ |--------|---------|
279
+ | `performGetStepUpMethods(user, context?)` | Which re-authentication methods this account has |
280
+ | `performRequestStepUpEmailCode(user, context?)` | Email a 6-digit re-authentication code |
281
+ | `performStepUpPasskeyOptions(user, context?)` | Options for re-authenticating with a passkey |
282
+ | `performReauthenticate(user, input, context?)` | Prove identity again; returns a step-up token |
283
+ | `performPasskeyRegistrationOptions(user, input, context?)` | Options for adding a passkey (needs a step-up token) |
284
+ | `performVerifyPasskeyRegistration(user, input, context?)` | Store the new passkey |
285
+ | `performPasskeyAuthenticationOptions(context?)` | Options for signing in (public) |
286
+ | `performVerifyPasskeyAuthentication(input, context?)` | Sign in; same response as `performLogin` |
287
+ | `performListPasskeys(user, context?)` | The user's passkeys |
288
+ | `performRenamePasskey(user, input, context?)` | Rename one |
289
+ | `performRemovePasskey(user, input, context?)` | Remove one (refused for the last way in) |
290
+
269
291
  **Other:**
270
292
 
271
293
  | Method | Purpose |
@@ -929,7 +951,7 @@ Treat this as *possession of a device-bound key that the client promises to
929
951
  gate*. It is a good second factor and a good convenience login. Before making it
930
952
  the sole factor for something sensitive, be clear that you are trusting the app,
931
953
  not the biometric. WebAuthn's `userVerification` flag is what actually attests to
932
- user verification, and is not this.
954
+ user verification, and is not this: for that, use [passkeys](#passkeys).
933
955
 
934
956
  #### The flow
935
957
 
@@ -1012,6 +1034,267 @@ same answer.
1012
1034
  biometric services are not registered at all, rather than silently accepting
1013
1035
  enrolments that can never authenticate.
1014
1036
 
1037
+ ### Passkeys
1038
+
1039
+ WebAuthn passkeys (since 0.16.0): registration for a signed-in user, then
1040
+ sign-in with no username at all. Enabled by `passkeyRepositoryInstance` plus
1041
+ `passkey.rp`, and needs the optional peer `@simplewebauthn/server` (^14,
1042
+ Node.js 20+).
1043
+
1044
+ ```typescript
1045
+ passkeyRepositoryInstance: myPasskeyRepo, // enables the capability
1046
+ passkey: {
1047
+ rp: {
1048
+ id: 'example.com', // the domain passkeys are bound to
1049
+ name: 'Example',
1050
+ origins: [
1051
+ 'https://app.example.com',
1052
+ 'android:apk-key-hash:<base64url SHA-256 of your signing certificate>',
1053
+ ],
1054
+ },
1055
+ // userVerification: 'required', // default; see below
1056
+ },
1057
+ ```
1058
+
1059
+ #### What a passkey sign-in proves
1060
+
1061
+ With `userVerification: 'required'` (the default): the user unlocked an
1062
+ authenticator **bound to this domain** that holds the registered key. Unlike
1063
+ the [biometric device key](#biometric-authentication), the authenticator itself
1064
+ attests that it verified the user, and a lookalike domain cannot use the
1065
+ credential. It does not prove *which* person unlocked the device, and a synced
1066
+ passkey is only as safe as the iCloud or Google account it syncs through.
1067
+
1068
+ **`'required'` adds no prompt for users.** On phones and laptops the Face ID,
1069
+ fingerprint or device PIN prompt *is* the passkey prompt, once per sign-in;
1070
+ sessions then continue through refresh tokens as usual. What `'required'`
1071
+ changes is that the server refuses an authenticator reporting that it did not
1072
+ verify the user, which in practice means a presence-only hardware key.
1073
+ `'preferred'` and `'discouraged'` accept those, and give up that guarantee.
1074
+
1075
+ #### The flow
1076
+
1077
+ ```
1078
+ Add a passkey (signed in)
1079
+ performReauthenticate({ password }) -> { stepUpToken } (see Step-Up)
1080
+ performPasskeyRegistrationOptions({ stepUpToken }) -> { challengeId, optionsJson }
1081
+ client: navigator.credentials.create(...)
1082
+ performVerifyPasskeyRegistration({ challengeId, responseJson, name? })
1083
+
1084
+ Sign in (signed out)
1085
+ performPasskeyAuthenticationOptions() -> { challengeId, optionsJson }
1086
+ client: navigator.credentials.get(...)
1087
+ performVerifyPasskeyAuthentication({ challengeId, responseJson }) -> AuthResponse
1088
+ ```
1089
+
1090
+ WebAuthn JSON crosses GraphQL as a `String`: send `optionsJson` to the platform
1091
+ API unchanged, and send back `JSON.stringify` of what it returns. In a browser:
1092
+
1093
+ ```typescript
1094
+ const { challengeId, optionsJson } = await passkeyAuthenticationOptions();
1095
+ const credential = await navigator.credentials.get({
1096
+ publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(JSON.parse(optionsJson)),
1097
+ });
1098
+ await passkeyLogin({ challengeId, responseJson: JSON.stringify(credential.toJSON()) });
1099
+ ```
1100
+
1101
+ (`@simplewebauthn/browser`'s `startRegistration({ optionsJSON })` /
1102
+ `startAuthentication({ optionsJSON })` do the same on browsers without the
1103
+ `parse…FromJSON` helpers.) The sign-in options also serve browser autofill:
1104
+ call `navigator.credentials.get` with `mediation: 'conditional'`, and fetch
1105
+ fresh options when they expire (120 s by default). On Flutter, use a plugin that
1106
+ exchanges WebAuthn JSON with Android Credential Manager and iOS
1107
+ `ASAuthorization`, and pass the same two strings through.
1108
+
1109
+ A consumer resolver, in the same shape as every other operation:
1110
+
1111
+ ```typescript
1112
+ @ObjectType() class PasskeyOptions { @Field() challengeId!: string; @Field() optionsJson!: string; }
1113
+ @ObjectType() class Passkey {
1114
+ @Field() credentialId!: string; @Field() name!: string;
1115
+ @Field() deviceType!: string; @Field() backedUp!: boolean;
1116
+ @Field() createdAt!: Date; @Field({ nullable: true }) lastUsedAt?: Date;
1117
+ }
1118
+ @ObjectType() class StepUpToken { @Field() stepUpToken!: string; @Field() expiresAt!: Date; }
1119
+ @InputType() class ReauthenticateInput {
1120
+ @Field({ nullable: true }) password?: string;
1121
+ @Field({ nullable: true }) emailCode?: string;
1122
+ @Field({ nullable: true }) passkeyChallengeId?: string;
1123
+ @Field({ nullable: true }) @MaxLength(16384) passkeyResponseJson?: string;
1124
+ }
1125
+ @InputType() class PasskeyRegistrationOptionsInput { @Field() stepUpToken!: string; }
1126
+ @InputType() class VerifyPasskeyInput {
1127
+ @Field() challengeId!: string;
1128
+ @Field() @MaxLength(16384) responseJson!: string;
1129
+ @Field({ nullable: true }) @MaxLength(64) name?: string;
1130
+ }
1131
+
1132
+ @Resolver()
1133
+ export class AppAuthResolver extends BaseAuthResolver<User> {
1134
+ @Mutation(() => StepUpToken) @UseGuards(JwtAuthGuard)
1135
+ reauthenticate(@Args('input') input: ReauthenticateInput, @CurrentUser() user: User, @Context() ctx: any) {
1136
+ return this.performReauthenticate(user, input, ctx);
1137
+ }
1138
+
1139
+ @Mutation(() => PasskeyOptions) @UseGuards(JwtAuthGuard)
1140
+ passkeyRegistrationOptions(@Args('input') input: PasskeyRegistrationOptionsInput, @CurrentUser() user: User, @Context() ctx: any) {
1141
+ return this.performPasskeyRegistrationOptions(user, input, ctx);
1142
+ }
1143
+
1144
+ @Mutation(() => Passkey) @UseGuards(JwtAuthGuard)
1145
+ verifyPasskeyRegistration(@Args('input') input: VerifyPasskeyInput, @CurrentUser() user: User, @Context() ctx: any) {
1146
+ return this.performVerifyPasskeyRegistration(user, input, ctx);
1147
+ }
1148
+
1149
+ @Mutation(() => PasskeyOptions)
1150
+ passkeyAuthenticationOptions(@Context() ctx: any) {
1151
+ return this.performPasskeyAuthenticationOptions(ctx);
1152
+ }
1153
+
1154
+ @Mutation(() => AuthResponse)
1155
+ passkeyLogin(@Args('input') input: VerifyPasskeyInput, @Context() ctx: any) {
1156
+ return this.performVerifyPasskeyAuthentication(input, ctx) as Promise<AuthResponse>;
1157
+ }
1158
+ }
1159
+ ```
1160
+
1161
+ `PasskeyService` (exported) has the same operations if you need them outside a
1162
+ resolver.
1163
+
1164
+ #### What the package guarantees
1165
+
1166
+ | | |
1167
+ |---|---|
1168
+ | Phishing | Origin and rpId are verified against `passkey.rp`; an assertion made for another site fails |
1169
+ | Replay | Every challenge is single use, consumed atomically **before** anything is checked, and burned by a failed attempt. It carries its purpose, user and realm, so a sign-in challenge cannot be spent on registration or step-up |
1170
+ | Adding a passkey | Needs a [step-up token](#step-up-re-authentication). A passkey survives a password change and logout-all, so a stolen session must not be able to add one |
1171
+ | Realms | A passkey signs in only to the realm it was registered in, checked on the stored record whatever the repository does |
1172
+ | User handle | Must match the stored one on sign-in (the library does not check it) |
1173
+ | Cloned authenticators | A counting authenticator's counter must increase, enforced by the package with a compare-and-set; a regression is refused and logged as `PASSKEY_COUNTER_REGRESSION`. Synced passkeys always report 0, which is accepted |
1174
+ | Account status | Sessions come from `issueAuthSession`, so a suspended user is refused after a valid assertion, with `ACCOUNT_INACTIVE` rather than the generic failure |
1175
+ | Enumeration | Sign-in options take no input; every sign-in failure is the same `401 Passkey authentication failed` |
1176
+ | Duplicates | A credential id already registered to anyone is refused (409), leaving the existing one untouched |
1177
+ | Last way in | Removing the only passkey of an account with no password and no social identity is refused (409) |
1178
+ | Rate limiting | Options are limited per user (registration, step-up) and per IP (sign-in); each verification consumes a challenge, so it is bounded by them |
1179
+
1180
+ #### Platform setup
1181
+
1182
+ None of this is visible to a compiler or a test suite; each item fails as an
1183
+ opaque error on the device.
1184
+
1185
+ | Platform | Needs |
1186
+ |---|---|
1187
+ | Web | The frontend on HTTPS, on a host equal to `rp.id` or under it, listed exactly in `rp.origins` (scheme, host, port; no path, no trailing slash) |
1188
+ | Android | `https://<rp.id>/.well-known/assetlinks.json` granting `delegate_permission/common.get_login_creds` to your package name and SHA-256 certificate fingerprint, **and** `android:apk-key-hash:<hash>` in `rp.origins` |
1189
+ | iOS | `https://<rp.id>/.well-known/apple-app-site-association` listing your app under `webcredentials.apps`, and `webcredentials:<rp.id>` in the app's Associated Domains entitlement. iOS reports the web origin `https://<rp.id>`, which must be in `rp.origins` |
1190
+
1191
+ The Android origin is the **base64url** SHA-256 of the signing certificate,
1192
+ not the colon-separated hex `keytool` prints. Convert it:
1193
+
1194
+ ```bash
1195
+ echo 'AB:CD:...:EF' | tr -d ':' | xxd -r -p | base64 | tr '+/' '-_' | tr -d '='
1196
+ ```
1197
+
1198
+ With Play App Signing, use the fingerprint of Google's app signing key (Play
1199
+ Console → App integrity), not your upload key. Boot refuses an Android origin
1200
+ that is not 43 base64url characters.
1201
+
1202
+ **Several brands, one API:** every `rp` field can be a resolver taking the
1203
+ request's realm, e.g. `id: (realm) => brands[realm].domain`. Resolved values are
1204
+ checked per call, since boot cannot know every realm.
1205
+
1206
+ #### Implementing `IPasskeyRepository`
1207
+
1208
+ Two methods must be one conditional statement each, never a read followed by a
1209
+ write:
1210
+
1211
+ ```typescript
1212
+ async consumeChallenge(challengeId: string) {
1213
+ const { count } = await prisma.passkeyChallenge.updateMany({
1214
+ where: { id: challengeId, used: false, expiresAt: { gt: new Date() } },
1215
+ data: { used: true, usedAt: new Date() },
1216
+ });
1217
+ if (count !== 1) return null;
1218
+ return this.loadChallenge(challengeId);
1219
+ }
1220
+
1221
+ async updateCounter({ credentialId, expectedCounter, newCounter, backedUp, lastUsedAt }) {
1222
+ const { count } = await prisma.passkeyCredential.updateMany({
1223
+ where: { credentialId, counter: expectedCounter },
1224
+ data: { counter: newCounter, backedUp, lastUsedAt },
1225
+ });
1226
+ return count === 1;
1227
+ }
1228
+ ```
1229
+
1230
+ And `createCredential` must throw `PasskeyCredentialExistsError` on a duplicate
1231
+ `credentialId` **for any user**, from a unique constraint (map Prisma's
1232
+ `P2002`). A reference schema:
1233
+
1234
+ ```prisma
1235
+ model PasskeyCredential {
1236
+ credentialId String @id // base64url, unique across all users
1237
+ userId String
1238
+ realm String? // required when realms are enabled
1239
+ publicKey String // base64url COSE key
1240
+ counter BigInt @default(0) // uint32 on the wire; Int is too small
1241
+ userHandle String
1242
+ transports String[]
1243
+ deviceType String
1244
+ backedUp Boolean
1245
+ aaguid String?
1246
+ name String
1247
+ createdAt DateTime @default(now())
1248
+ lastUsedAt DateTime?
1249
+ isActive Boolean @default(true)
1250
+ metadata Json?
1251
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
1252
+ @@index([userId, realm])
1253
+ }
1254
+
1255
+ model PasskeyChallenge {
1256
+ id String @id @default(uuid())
1257
+ challenge String
1258
+ purpose String // registration | authentication | step-up
1259
+ userId String? // not a foreign key
1260
+ realm String?
1261
+ userHandle String? // registration only
1262
+ expiresAt DateTime
1263
+ used Boolean @default(false)
1264
+ usedAt DateTime?
1265
+ @@index([expiresAt])
1266
+ }
1267
+ ```
1268
+
1269
+ `getCredential` returns deactivated credentials too; the package decides. Run
1270
+ the concurrency tests in `src/repositories/in-memory-passkey.repository.spec.ts`
1271
+ against your adapter. `InMemoryPasskeyRepository` is exported for tests and
1272
+ single-instance development.
1273
+
1274
+ ### Step-Up Re-authentication
1275
+
1276
+ A signed-in user proves again who they are and receives a short-lived **step-up
1277
+ token** (5 minutes by default) for a protected action. Adding a passkey requires
1278
+ one.
1279
+
1280
+ | Proof | Available when |
1281
+ |---|---|
1282
+ | `{ password }` | The account has a password. **Failures count toward [lockout](#brute-force-protection)**, so a stolen session cannot guess it freely |
1283
+ | `{ passkeyChallengeId, passkeyResponseJson }` | Passkeys are configured and the user has one (options from `performStepUpPasskeyOptions`) |
1284
+ | `{ emailCode }` | `verificationRepositoryInstance` is set and the email service implements `sendStepUpCodeEmail` (`ConfigurableEmailService` does). Always a 6-digit code, never a link; one email a minute |
1285
+
1286
+ `performGetStepUpMethods` says which apply, so the client shows only working
1287
+ buttons. Failures are `401 Re-authentication failed`; an action that needs a
1288
+ token answers `STEP_UP_REQUIRED` (403), and a method the account lacks
1289
+ `STEP_UP_UNAVAILABLE` (403).
1290
+
1291
+ The token is signed with a key derived from `jwtSecret` (HKDF), never with
1292
+ `jwtSecret` itself, so it can never pass as an access token. It is bound to the
1293
+ user and realm.
1294
+
1295
+ **Email codes use a new verification type, `step-up`.** If your verification
1296
+ repository stores the type in a database enum, add the value.
1297
+
1015
1298
  ### Brute Force Protection
1016
1299
 
1017
1300
  Provide a `bruteForceRepositoryInstance` and the module tracks failed login attempts and temporarily locks accounts. Without one, `NoOpBruteForceRepository` is used and no account is ever locked; there is no flag to set. The lockout policy (attempt thresholds, lockout duration) is determined by your `IBruteForceRepository` implementation.
@@ -1228,10 +1511,12 @@ lifecycleHooksInstance: {
1228
1511
  onAccountLocked(userId, email, ip, lockSeconds, realm) {
1229
1512
  /* send account-locked notification email, alert security tooling */
1230
1513
  },
1514
+ async onPasskeyRegistered(user, passkey, realm) { /* email "a passkey was added" */ },
1515
+ async onPasskeyRemoved(user, passkey, realm) { /* email "a passkey was removed" */ },
1231
1516
  }
1232
1517
  ```
1233
1518
 
1234
- All hooks are optional. Async hooks are awaited but failures are logged and do not block the auth operation. `onAuthFailure` and `onAccountLocked` are synchronous (fire-and-forget) — both are security signals and the underlying state (lock recorded, attempt logged) is already persisted by the time the hook fires, so hook failures must not roll it back.
1519
+ All hooks are optional. Async hooks are awaited but failures are logged and do not block the auth operation; the passkey hooks are not awaited, so a slow mail send does not hold up the response. **Wire `onPasskeyRegistered` to a notification email**: it is how a user learns of a passkey they did not add. `onAuthFailure` and `onAccountLocked` are synchronous (fire-and-forget) — both are security signals and the underlying state (lock recorded, attempt logged) is already persisted by the time the hook fires, so hook failures must not roll it back.
1235
1520
 
1236
1521
  `onAccountLocked` fires from `BruteForceProtectionService.recordFailedAttempt` on the transition from "not locked" → "locked". Subsequent failed attempts while the account remains locked do **not** re-fire (use `onAuthFailure` for per-attempt signal). Wire it to send the account-locked email yourself — the package no longer ships a `sendAccountLockedEmail` method on `IEmailService`; notification surface area beyond verification, password-reset, and password-changed is consumer-owned via this hook.
1237
1522
 
@@ -1460,6 +1745,28 @@ without it is reported at boot, not refused.
1460
1745
  | `challengeExpirySeconds` | `number` | `60` | Short on purpose: it bounds replay |
1461
1746
  | `challengeRateLimit` | `{ maxAttempts, windowMs }` | `5 / 60s` | Per credential. **Requires `rateLimiterInstance`** — the same guardrail as `bruteForce.ipRateLimit`, because per-replica counters would make the limit silently looser. A per-IP limit at ten times this bound also applies when you pass `ipAddress` |
1462
1747
 
1748
+ ### Passkey Options (`passkey`)
1749
+
1750
+ Read only when `passkeyRepositoryInstance` is provided; without it this block is
1751
+ reported at boot as ignored. With it, `rp` is required.
1752
+
1753
+ | Option | Type | Default | Description |
1754
+ |--------|------|---------|-------------|
1755
+ | `rp.id` | `string \| (realm?) => string` | — | The registrable domain passkeys are bound to. No scheme, port or path; not an IP |
1756
+ | `rp.name` | `string \| (realm?) => string` | — | Shown by some authenticators |
1757
+ | `rp.origins` | `string[] \| (realm?) => string[]` | — | Exact origins accepted, each `rp.id` or a subdomain of it, https except localhost; Android `android:apk-key-hash:` origins |
1758
+ | `userVerification` | `'required' \| 'preferred' \| 'discouraged'` | `'required'` | See [What a passkey sign-in proves](#what-a-passkey-sign-in-proves) |
1759
+ | `registrationTimeoutSeconds` | `number` | `300` | Registration ceremony lifetime |
1760
+ | `authenticationTimeoutSeconds` | `number` | `120` | Sign-in and step-up ceremony lifetime |
1761
+ | `rateLimit` | `{ maxAttempts, windowMs }` | `10 / 60s` | Options per user (registration, step-up) and per IP (sign-in). **Requires `rateLimiterInstance`** when set |
1762
+ | `userDisplayName` | `(user) => string` | the email | What authenticators show for the account |
1763
+
1764
+ ### Step-Up Options (`stepUp`)
1765
+
1766
+ | Option | Type | Default | Description |
1767
+ |--------|------|---------|-------------|
1768
+ | `ttlSeconds` | `number` | `300` | Step-up token lifetime, 1 to 3600 |
1769
+
1463
1770
  ### Optional Instance Options
1464
1771
 
1465
1772
  | Option | Interface | Fallback |
@@ -1469,7 +1776,8 @@ without it is reported at boot, not refused.
1469
1776
  | `lifecycleHooksInstance` | `IAuthLifecycleHooks` | `{}` (no-op) |
1470
1777
  | `verificationRepositoryInstance` | `IVerificationRepository` | `NoOpVerificationRepository` |
1471
1778
  | `bruteForceRepositoryInstance` | `IBruteForceRepository` | `NoOpBruteForceRepository` |
1472
- | `biometricRepositoryInstance` | `IBiometricRepository` | `NoOpBiometricRepository` |
1779
+ | `biometricRepositoryInstance` | `IBiometricRepository` | none: biometrics disabled |
1780
+ | `passkeyRepositoryInstance` | `IPasskeyRepository` | none: passkeys disabled |
1473
1781
  | `authLoggerInstance` | `IAuthLogger` | `ConsoleAuthLogger` |
1474
1782
  | `tenantRepositoryInstance` | `ITenantRepository` | `null` |
1475
1783
  | `tenantExtractorInstance` | `ITenantExtractor` | `null` |
@@ -9,6 +9,8 @@ import { IRefreshTokenRepository } from './interfaces/refresh-token-repository.i
9
9
  import { IVerificationRepository } from './interfaces/verification-repository.interface';
10
10
  import { IBruteForceRepository } from './interfaces/brute-force-repository.interface';
11
11
  import { IBiometricRepository } from './interfaces/biometric-repository.interface';
12
+ import { IPasskeyRepository } from './interfaces/passkey-repository.interface';
13
+ import { PasskeyRelyingPartyConfig } from './utils/passkey-rp';
12
14
  import { IAuthLogger } from './interfaces/auth-logger.interface';
13
15
  import { ITenantRepository } from './interfaces/tenant-repository.interface';
14
16
  import { ITenantExtractor } from './interfaces/tenant-extractor.interface';
@@ -32,6 +34,7 @@ export interface AuthModuleOptions {
32
34
  verificationRepositoryInstance?: IVerificationRepository;
33
35
  bruteForceRepositoryInstance?: IBruteForceRepository;
34
36
  biometricRepositoryInstance?: IBiometricRepository;
37
+ passkeyRepositoryInstance?: IPasskeyRepository;
35
38
  authLoggerInstance?: IAuthLogger;
36
39
  refreshTokenSecret?: string;
37
40
  verificationCodeSecret?: string;
@@ -130,6 +133,20 @@ export interface AuthModuleOptions {
130
133
  windowMs: number;
131
134
  };
132
135
  };
136
+ passkey?: {
137
+ rp: PasskeyRelyingPartyConfig;
138
+ userVerification?: 'required' | 'preferred' | 'discouraged';
139
+ registrationTimeoutSeconds?: number;
140
+ authenticationTimeoutSeconds?: number;
141
+ rateLimit?: {
142
+ maxAttempts: number;
143
+ windowMs: number;
144
+ };
145
+ userDisplayName?: (user: IAuthUser) => string;
146
+ };
147
+ stepUp?: {
148
+ ttlSeconds?: number;
149
+ };
133
150
  verification?: {
134
151
  tokenLength?: number;
135
152
  tokenExpiresInMinutes?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../src/auth.module.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../src/auth.module.ts"],"names":[],"mappings":"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"}