@ambushsoftworks/nestjs-auth-graphql 0.11.0 → 0.14.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.
Files changed (105) hide show
  1. package/CHANGELOG.md +300 -0
  2. package/README.md +411 -3
  3. package/dist/auth.module.d.ts +15 -1
  4. package/dist/auth.module.d.ts.map +1 -1
  5. package/dist/auth.module.js +114 -16
  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/decorators/require-scopes.decorator.d.ts +2 -0
  12. package/dist/decorators/require-scopes.decorator.d.ts.map +1 -0
  13. package/dist/decorators/require-scopes.decorator.js +8 -0
  14. package/dist/decorators/require-scopes.decorator.js.map +1 -0
  15. package/dist/guards/csrf.guard.d.ts +2 -0
  16. package/dist/guards/csrf.guard.d.ts.map +1 -1
  17. package/dist/guards/csrf.guard.js +9 -2
  18. package/dist/guards/csrf.guard.js.map +1 -1
  19. package/dist/guards/scope.guard.d.ts +8 -0
  20. package/dist/guards/scope.guard.d.ts.map +1 -0
  21. package/dist/guards/scope.guard.js +53 -0
  22. package/dist/guards/scope.guard.js.map +1 -0
  23. package/dist/index.d.ts +6 -6
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +6 -6
  26. package/dist/index.js.map +1 -1
  27. package/dist/interfaces/api-key-repository.interface.d.ts +3 -0
  28. package/dist/interfaces/api-key-repository.interface.d.ts.map +1 -1
  29. package/dist/interfaces/biometric-repository.interface.d.ts +29 -17
  30. package/dist/interfaces/biometric-repository.interface.d.ts.map +1 -1
  31. package/dist/interfaces/biometric-verifier.interface.d.ts +10 -0
  32. package/dist/interfaces/biometric-verifier.interface.d.ts.map +1 -0
  33. package/dist/interfaces/{magic-link-repository.interface.js → biometric-verifier.interface.js} +1 -1
  34. package/dist/interfaces/biometric-verifier.interface.js.map +1 -0
  35. package/dist/resolvers/base-auth.resolver.d.ts.map +1 -1
  36. package/dist/resolvers/base-auth.resolver.js +0 -15
  37. package/dist/resolvers/base-auth.resolver.js.map +1 -1
  38. package/dist/services/auth.service.d.ts.map +1 -1
  39. package/dist/services/auth.service.js +10 -3
  40. package/dist/services/auth.service.js.map +1 -1
  41. package/dist/services/biometric-auth.service.d.ts +47 -17
  42. package/dist/services/biometric-auth.service.d.ts.map +1 -1
  43. package/dist/services/biometric-auth.service.js +109 -68
  44. package/dist/services/biometric-auth.service.js.map +1 -1
  45. package/dist/services/biometric-challenge.service.d.ts +27 -0
  46. package/dist/services/biometric-challenge.service.d.ts.map +1 -0
  47. package/dist/services/biometric-challenge.service.js +116 -0
  48. package/dist/services/biometric-challenge.service.js.map +1 -0
  49. package/dist/services/biometric-verification.service.d.ts.map +1 -1
  50. package/dist/services/biometric-verification.service.js +4 -0
  51. package/dist/services/biometric-verification.service.js.map +1 -1
  52. package/dist/services/verification.service.d.ts +2 -1
  53. package/dist/services/verification.service.d.ts.map +1 -1
  54. package/dist/services/verification.service.js +38 -8
  55. package/dist/services/verification.service.js.map +1 -1
  56. package/dist/strategies/api-key.strategy.d.ts +6 -1
  57. package/dist/strategies/api-key.strategy.d.ts.map +1 -1
  58. package/dist/strategies/api-key.strategy.js +40 -6
  59. package/dist/strategies/api-key.strategy.js.map +1 -1
  60. package/dist/strategies/external-jwt.strategy.d.ts +19 -0
  61. package/dist/strategies/external-jwt.strategy.d.ts.map +1 -0
  62. package/dist/strategies/external-jwt.strategy.js +124 -0
  63. package/dist/strategies/external-jwt.strategy.js.map +1 -0
  64. package/dist/strategies/jwt.strategy.d.ts.map +1 -1
  65. package/dist/strategies/jwt.strategy.js +1 -0
  66. package/dist/strategies/jwt.strategy.js.map +1 -1
  67. package/dist/test-utils/mock-repositories.d.ts.map +1 -1
  68. package/dist/test-utils/mock-repositories.js +8 -7
  69. package/dist/test-utils/mock-repositories.js.map +1 -1
  70. package/dist/utils/provider-helpers.d.ts +6 -0
  71. package/dist/utils/provider-helpers.d.ts.map +1 -1
  72. package/dist/utils/provider-helpers.js +4 -0
  73. package/dist/utils/provider-helpers.js.map +1 -1
  74. package/dist/utils/verification-base-url.d.ts +2 -0
  75. package/dist/utils/verification-base-url.d.ts.map +1 -0
  76. package/dist/utils/verification-base-url.js +19 -0
  77. package/dist/utils/verification-base-url.js.map +1 -0
  78. package/dist/verifiers/es256-device-key.verifier.d.ts +14 -0
  79. package/dist/verifiers/es256-device-key.verifier.d.ts.map +1 -0
  80. package/dist/verifiers/es256-device-key.verifier.js +42 -0
  81. package/dist/verifiers/es256-device-key.verifier.js.map +1 -0
  82. package/package.json +8 -2
  83. package/dist/interfaces/magic-link-repository.interface.d.ts +0 -6
  84. package/dist/interfaces/magic-link-repository.interface.d.ts.map +0 -1
  85. package/dist/interfaces/magic-link-repository.interface.js.map +0 -1
  86. package/dist/interfaces/password-reset-strategy.interface.d.ts +0 -7
  87. package/dist/interfaces/password-reset-strategy.interface.d.ts.map +0 -1
  88. package/dist/interfaces/password-reset-strategy.interface.js +0 -3
  89. package/dist/interfaces/password-reset-strategy.interface.js.map +0 -1
  90. package/dist/repositories/noop-biometric.repository.d.ts +0 -26
  91. package/dist/repositories/noop-biometric.repository.d.ts.map +0 -1
  92. package/dist/repositories/noop-biometric.repository.js +0 -56
  93. package/dist/repositories/noop-biometric.repository.js.map +0 -1
  94. package/dist/repositories/noop-magic-link.repository.d.ts +0 -9
  95. package/dist/repositories/noop-magic-link.repository.d.ts.map +0 -1
  96. package/dist/repositories/noop-magic-link.repository.js +0 -37
  97. package/dist/repositories/noop-magic-link.repository.js.map +0 -1
  98. package/dist/strategies/magic-link.strategy.d.ts +0 -16
  99. package/dist/strategies/magic-link.strategy.d.ts.map +0 -1
  100. package/dist/strategies/magic-link.strategy.js +0 -80
  101. package/dist/strategies/magic-link.strategy.js.map +0 -1
  102. package/dist/strategies/verification-code.strategy.d.ts +0 -11
  103. package/dist/strategies/verification-code.strategy.d.ts.map +0 -1
  104. package/dist/strategies/verification-code.strategy.js +0 -44
  105. package/dist/strategies/verification-code.strategy.js.map +0 -1
package/README.md CHANGED
@@ -13,10 +13,14 @@ Production-grade authentication module for NestJS GraphQL + REST APIs. JWT, cook
13
13
  - [Multi-Tenancy](#multi-tenancy)
14
14
  - [Realm-Based Identity Isolation](#realm-based-identity-isolation)
15
15
  - [API Key Authentication](#api-key-authentication)
16
+ - [External JWTs](#external-jwts)
16
17
  - [Email System](#email-system)
17
18
  - [Verification Modes](#verification-modes)
19
+ - [Phone \& SMS Verification](#phone--sms-verification)
18
20
  - [OAuth](#oauth)
21
+ - [Biometric Authentication](#biometric-authentication)
19
22
  - [Brute Force Protection](#brute-force-protection)
23
+ - [Password Reset](#password-reset)
20
24
  - [Password Policy](#password-policy)
21
25
  - [Lifecycle Hooks](#lifecycle-hooks)
22
26
  - [Account Status](#account-status)
@@ -33,12 +37,17 @@ Production-grade authentication module for NestJS GraphQL + REST APIs. JWT, cook
33
37
  - [CSRF Options](#csrf-options-csrf)
34
38
  - [Composable Email](#composable-email-email)
35
39
  - [Verification Options](#verification-options-verification)
40
+ - [Biometric Options (`biometric`)](#biometric-options-biometric)
41
+ - [SendGrid Options (`sendgrid`)](#sendgrid-options-sendgrid)
42
+ - [Twilio Options (`twilio`)](#twilio-options-twilio)
36
43
  - [Optional Instance Options](#optional-instance-options)
37
44
  - [Decorators](#decorators)
38
45
  - [Guards](#guards)
39
46
  - [GraphQL Subscriptions](#graphql-subscriptions)
40
47
  - [Utilities](#utilities)
41
48
  - [Security Features](#security-features)
49
+ - [Upgrading from 0.9.x](#upgrading-from-09x)
50
+ - [Migrating to v0.12.0](#migrating-to-v0120)
42
51
  - [Migrating to v0.11.0](#migrating-to-v0110)
43
52
  - [Migrating to v0.10.0](#migrating-to-v0100)
44
53
  - [Migrating to v0.9.0](#migrating-to-v090)
@@ -559,6 +568,73 @@ The `ApiKeyStrategy` hashes the bearer token with SHA-256 and calls `findByKeyHa
559
568
 
560
569
  Before 0.10.0 the API key strategy rejected an unknown bearer token itself, which stopped the chain: `['api-key', 'jwt']` rejected every JWT.
561
570
 
571
+ #### Key options
572
+
573
+ | Option | Example | Effect |
574
+ |--------|---------|--------|
575
+ | `apiKey.headerName` | `'X-API-Key'` | A header carrying the raw key, read before `Authorization: Bearer`, which keeps working. `CsrfGuard` treats a request carrying it as credentialed, as it already does for `Authorization` |
576
+ | `apiKey.prefix` | `'ait_'` | The prefix every key you issue starts with. See below |
577
+
578
+ Both are read only with `apiKeyRepositoryInstance`, and `apiKey.prefix` without it warns at boot. `headerName` must be a header name other than `Authorization`, and `prefix` must not be empty -- an empty one matches every token, so every unknown bearer token, JWTs included, would be refused. Boot fails on either.
579
+
580
+ **A prefix makes an unknown key unambiguous.** Without one, the strategy cannot tell a mistyped key from a JWT:
581
+
582
+ | Token | Without `prefix` | With `prefix` |
583
+ |-------|------------------|---------------|
584
+ | Does not start with the prefix (a JWT, say) | Looked up, then passed to the next strategy | Passed to the next strategy, with no lookup |
585
+ | Starts with it, matches no key | Passed to the next strategy; a single-strategy guard answers a generic 401 | `401 Invalid API key` -- it cannot be a JWT, so no other strategy tries it |
586
+ | Matches a key | Authenticated, unless the key is inactive or expired | The same |
587
+
588
+ #### Expiry, scopes and last use
589
+
590
+ `IApiKeyAccount` carries optional `scopes?: string[]` and `expiresAt?: Date | null`, and `IApiKeyRepository` may implement `touchLastUsed?(id)`. Existing repositories keep working.
591
+
592
+ - **Expiry.** A key whose `expiresAt` has passed is refused with `401 API key has expired`, and no other strategy tries it. A key without one never expires.
593
+ - **Scopes.** Mark the operation and register `ScopeGuard` after your authentication guard:
594
+
595
+ ```typescript
596
+ @Get('tickets')
597
+ @UseGuards(createAuthGuard(['api-key', 'jwt']), ScopeGuard)
598
+ @RequireScopes('tickets:read')
599
+ listTickets() { /* ... */ }
600
+ ```
601
+
602
+ A key must hold every listed scope. One that does not gets 403 with `{ message: 'Insufficient scope', code: 'INSUFFICIENT_SCOPE', requiredScopes, statusCode: 403 }`, naming what the operation requires. A key with no `scopes` holds none. **Signed-in people pass**: scopes restrict keys, while a person's access is `PermissionGuard`'s job. With no authenticated principal at all, `ScopeGuard` answers 401 -- which is why it goes after the auth guard.
603
+ - **Last use.** `touchLastUsed(id)` is called once per successful match, and only then -- never for a key that is refused. It is not awaited: a failure is logged and never fails the request.
604
+
605
+ ### External JWTs
606
+
607
+ `createExternalJwtStrategy(name, options)` verifies tokens another system signs -- each app's backend signing for its own users, say. It registers a separate Passport strategy under `name`, with no realm check and no user lookup, so the package's own `jwt` strategy is untouched.
608
+
609
+ ```typescript
610
+ export const CustomerJwtStrategy = createExternalJwtStrategy('customer-jwt', {
611
+ inject: [AppSecretsService], // optional; pass a plain options object instead
612
+ useFactory: (secrets: AppSecretsService) => ({
613
+ algorithms: ['HS256'], // required
614
+ audience: 'ambush-desk',
615
+ secretProvider: (kid) => secrets.findSecret(kid),
616
+ mapClaims: (claims) => ({ id: claims.sub, app: claims.app, segments: claims.segments }),
617
+ }),
618
+ });
619
+
620
+ // providers: [CustomerJwtStrategy]
621
+ // @UseGuards(createAuthGuard(['customer-jwt']))
622
+ ```
623
+
624
+ | Option | Default | Description |
625
+ |--------|---------|-------------|
626
+ | `secretProvider(kid, request)` | -- | The key that verifies a token: a shared secret for `HS*`, a PEM public key for `RS*`, `PS*` and `ES*`. May be async. `null` rejects the token; so does a throw, which is logged |
627
+ | `algorithms` | -- | **Required.** The algorithms the issuer signs with |
628
+ | `issuer`, `audience` | -- | Required `iss` / `aud`, when set |
629
+ | `clockToleranceSec` | `0` | Clock skew allowed on `exp` and `nbf` |
630
+ | `maxTokenBytes` | `8192` | A longer token is refused before anything parses it |
631
+ | `mapClaims(payload)` | the payload | Builds `request.user`, arrays and custom claims intact. `null`, `undefined` or a throw rejects the token |
632
+ | `jwtFromRequest(request)` | `Authorization: Bearer` | Where the token comes from |
633
+
634
+ **Algorithms are pinned, one family at a time.** Boot fails with `InvalidAuthConfigException` for missing or empty `algorithms`, for `none`, for an algorithm jsonwebtoken does not know, and for HMAC (`HS*`) mixed with asymmetric algorithms -- the mix that lets a public key be used as an HMAC secret. `'jwt'` and `'api-key'` are refused as names, since Passport would replace the package's own strategy.
635
+
636
+ **Every rejection fails softly**, so the strategy composes: `createAuthGuard(['customer-jwt', 'jwt'])` accepts either kind of token, in either order, and answers 401 when both fail.
637
+
562
638
  ### Email System
563
639
 
564
640
  The email system uses a composable architecture: a **sender** (transport) and a **template renderer** (HTML generation).
@@ -688,6 +764,40 @@ variable (deprecated — logged once). With neither, code-mode emails carry no
688
764
  link and nothing is logged: the code is in the body, so no link is needed. The
689
765
  code itself is never placed in a query string in either mode.
690
766
 
767
+ #### One API, several brands: `baseUrl` per realm
768
+
769
+ With [realms](#realm-based-identity-isolation) enabled, one deployment serves
770
+ several frontends and a link must open on the site the user actually came from.
771
+ `baseUrl` accepts a resolver as well as a string; it is called with the realm of
772
+ the request the credential is being issued for:
773
+
774
+ ```typescript
775
+ const SITES: Record<string, string> = {
776
+ 'site-a': 'https://a.example.com',
777
+ 'site-b': 'https://b.example.com',
778
+ };
779
+
780
+ verification: {
781
+ baseUrl: (realm?: string) => SITES[realm ?? ''] ?? 'https://www.example.com',
782
+ },
783
+ ```
784
+
785
+ It applies to both modes — the token link and the code page link — because both
786
+ are built from the same resolved base. It is called once per link, so resolve
787
+ from a map rather than a query, and it must be synchronous.
788
+
789
+ **Boot validation is weaker for a resolver, by necessity.** A string is checked
790
+ in full at startup. A resolver is only called once, with `undefined`, so the
791
+ realm-less case is checked and a per-realm return value is not — there is no
792
+ request at startup to supply a realm. What it returns for a specific realm is
793
+ checked when the link is built, and the two modes differ exactly as they do
794
+ elsewhere: token mode throws, because the link carries the only copy of the
795
+ credential; code mode logs a warning and sends the email without a link,
796
+ because the code is in the body.
797
+
798
+ Returning a value for `realm === undefined` is required. A request exempted by
799
+ `realm.skip`, or a single-realm deployment, has no realm.
800
+
691
801
  **Custom `IEmailService` implementations.** Both send methods receive the
692
802
  credential and its URL, and the mode determines which one is actionable:
693
803
 
@@ -702,6 +812,45 @@ link. `expiresInMinutes` reflects the mode's real expiry, so render it rather
702
812
  than hardcoding a duration. Both trailing parameters are optional, so existing
703
813
  implementations continue to compile.
704
814
 
815
+ ### Phone & SMS Verification
816
+
817
+ An authenticated user adds a phone number, receives a 6-digit code by SMS, and
818
+ confirms it. All five methods take the current user, so they sit behind your
819
+ authentication guard — this is account management, not a sign-in path.
820
+
821
+ | Method | Purpose |
822
+ |---|---|
823
+ | `performSendPhoneVerification(input, user)` | Store the number and send a code |
824
+ | `performVerifyPhone(input, user)` | Confirm the code, mark the number verified |
825
+ | `performResendPhoneVerification(phoneNumber, user)` | Send again, subject to the 60-second cooldown |
826
+ | `performRemovePhoneNumber(user)` | Clear the number and its verified state |
827
+ | `performPhoneVerificationStatus(user)` | Whether a number is present and verified |
828
+
829
+ Provide `smsServiceInstance` and `verificationRepositoryInstance`. `ISmsService`
830
+ has a single method, so the seam is small:
831
+
832
+ ```typescript
833
+ export class TwilioSmsService implements ISmsService {
834
+ async sendVerificationSms(phoneNumber: string, code: string): Promise<void> {
835
+ await this.client.messages.create({ to: phoneNumber, body: `Your code is ${code}` });
836
+ }
837
+ }
838
+ ```
839
+
840
+ Two things worth knowing:
841
+
842
+ - **SMS is code-only.** `features.verificationMode: 'token'` governs email
843
+ verification and password reset. A phone always receives a 6-digit code,
844
+ because a link is not usable from a text message in the same way — so
845
+ `verification.baseUrl` is irrelevant here.
846
+ - **Omitting `smsServiceInstance` does not fail loudly.** The package substitutes
847
+ a no-op that logs, so codes are generated and stored but never delivered.
848
+ Verification then only succeeds for someone reading your application logs.
849
+
850
+ The number's realm is scoped like any other identity field: with realms enabled,
851
+ `findByPhoneNumber` receives the realm, so the same number can exist once per
852
+ realm.
853
+
705
854
  ### OAuth
706
855
 
707
856
  Google and Facebook OAuth with encrypted token storage (AES-256-GCM).
@@ -755,6 +904,110 @@ It sits beside `useFactory` because Nest fixes a module's controllers before asy
755
904
 
756
905
  With realms enabled, a request without a realm gets `400 Realm required` first. Before 0.10.0 the lockout, inactive-account, rate-limit and unconfigured-provider cases answered 500.
757
906
 
907
+ ### Biometric Authentication
908
+
909
+ A device holds an ECDSA P-256 keypair, gated behind the OS biometric prompt. The
910
+ server stores the public key and verifies a signature over a challenge it issued.
911
+
912
+ ```typescript
913
+ biometricRepositoryInstance: myBiometricRepo, // enables the capability
914
+ biometric: {
915
+ challengeExpirySeconds: 60, // default
916
+ challengeRateLimit: { maxAttempts: 5, windowMs: 60_000 }, // needs rateLimiterInstance
917
+ },
918
+ ```
919
+
920
+ #### ⚠ What a successful authentication actually proves
921
+
922
+ **It proves the client still holds the private key. It does not prove a biometric
923
+ check happened.** Nothing in an ECDSA signature attests to that, and the server
924
+ cannot distinguish a key held in a hardware enclave from one generated in
925
+ software. Whether a fingerprint was scanned — or a PIN accepted instead, which
926
+ most mobile biometric APIs allow by default — is the client's word.
927
+
928
+ Treat this as *possession of a device-bound key that the client promises to
929
+ gate*. It is a good second factor and a good convenience login. Before making it
930
+ the sole factor for something sensitive, be clear that you are trusting the app,
931
+ not the biometric. WebAuthn's `userVerification` flag is what actually attests to
932
+ user verification, and is not this.
933
+
934
+ #### The flow
935
+
936
+ ```typescript
937
+ // 1. Enrol, authenticated. The package generates the credential id — keep it
938
+ // on the device alongside the private key.
939
+ const { credentialId } = await biometricAuth.enrolCredential({
940
+ userId: user.id,
941
+ publicKey, // PEM, SPKI
942
+ deviceName: 'iPhone 15',
943
+ metadata: { yourDeviceString: '...' }, // optional, opaque to the package
944
+ });
945
+
946
+ // 2. Request a challenge. No user id — the caller is usually signed out.
947
+ const challenge = await biometricAuth.requestChallenge(credentialId, {
948
+ ipAddress: req.ip,
949
+ });
950
+ if (!challenge) { /* rate limited */ }
951
+
952
+ // 3. The client signs `challenge.challenge` (base64) with the private key.
953
+
954
+ // 4. Verify and receive a session.
955
+ const session = await biometricAuth.authenticateWithBiometric(
956
+ { challengeId: challenge.challengeId, credentialId, signature },
957
+ { res, realm, ipAddress: req.ip },
958
+ );
959
+ ```
960
+
961
+ Also `listCredentials(userId)` for a device list and `removeCredential(userId,
962
+ credentialId)` to deactivate one.
963
+
964
+ #### What the package guarantees
965
+
966
+ | | |
967
+ |---|---|
968
+ | Challenge | 32 random bytes, single use, 60s default |
969
+ | Replay | A challenge is consumed **atomically** before anything is checked, so a retry loses the race — and a failed attempt still burns it |
970
+ | Cross-credential | A challenge issued for one credential cannot be answered with another's key |
971
+ | Algorithm | Pinned **per credential**. A credential enrolled as ES256 is only verified as ES256; no verifier for its algorithm means refusal, not a fallback |
972
+ | Account status | The session comes from the same sink as every other login, so a suspended or soft-deleted user is refused **after** a valid signature |
973
+ | Enumeration | Every biometric failure returns the same 401, and a challenge is issued even for a credential that does not exist |
974
+ | Rate limiting | Per credential, and per IP so varying the credential id cannot evade it |
975
+
976
+ #### Implementing `IBiometricRepository`
977
+
978
+ One method has a contract you cannot satisfy with a read followed by a write:
979
+
980
+ ```typescript
981
+ async consumeChallenge(challengeId: string) {
982
+ // Atomic: mark used and return it, only if it was unused and unexpired.
983
+ const { count } = await prisma.biometricChallenge.updateMany({
984
+ where: { id: challengeId, used: false, expiresAt: { gt: new Date() } },
985
+ data: { used: true, usedAt: new Date() },
986
+ });
987
+ if (count !== 1) return null; // someone else claimed it, or it expired
988
+ return this.load(challengeId);
989
+ }
990
+ ```
991
+
992
+ Read-then-write lets two concurrent requests with one challenge both succeed,
993
+ which is the replay single use exists to prevent.
994
+
995
+ Two more things your schema needs to know:
996
+
997
+ - **`credentialId` on a challenge is not a foreign key.** A challenge is stored
998
+ for credential ids that do not exist, so that the signed-out request cannot be
999
+ used to discover which credentials are enrolled.
1000
+ - **No uniqueness on `deviceName` or any device string.** It is a display label,
1001
+ never matched on. Key rotation is enrol-new then deactivate-old.
1002
+
1003
+ `getCredential` must return deactivated credentials rather than hiding them — the
1004
+ package decides, so that a deactivated credential and an unknown one produce the
1005
+ same answer.
1006
+
1007
+ **There is no no-op fallback.** Omit `biometricRepositoryInstance` and the
1008
+ biometric services are not registered at all, rather than silently accepting
1009
+ enrolments that can never authenticate.
1010
+
758
1011
  ### Brute Force Protection
759
1012
 
760
1013
  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.
@@ -859,6 +1112,78 @@ async changePassword(
859
1112
 
860
1113
  `issueAuthSession(userId, res?, realm?)` mints a new access + refresh pair, persists the refresh token, and (when `features.cookieAuth` is enabled and `res` is supplied) sets the auth cookies on the response. The caller is responsible for verifying the user's identity — `issueAuthSession` takes a `userId` and trusts it. Pair it only with flows that have already authenticated the user (`changePassword`, MFA enrollment completion, admin-impersonation reissue, etc.). Emits `SecurityEvent.SESSION_ISSUED`.
861
1114
 
1115
+ ### Password Reset
1116
+
1117
+ A reset is two calls: `performRequestPasswordReset` sends a 6-digit code, and
1118
+ `performResetPassword` redeems it. `performChangePassword` is the separate,
1119
+ authenticated path for a signed-in user who knows their current password.
1120
+
1121
+ ```typescript
1122
+ @Mutation(() => PasswordResetResponse)
1123
+ requestPasswordReset(@Args('input') input: RequestPasswordResetInput, @Context() ctx: any) {
1124
+ return this.performRequestPasswordReset(input, ctx);
1125
+ }
1126
+
1127
+ @Mutation(() => PasswordResetResponse)
1128
+ resetPassword(@Args('input') input: ResetPasswordInput, @Context() ctx: any) {
1129
+ return this.performResetPassword(input, ctx);
1130
+ }
1131
+ ```
1132
+
1133
+ It needs `verificationRepositoryInstance` to store the code and
1134
+ `emailServiceInstance` to deliver it. Without the first, codes are logged rather
1135
+ than stored and no reset can complete.
1136
+
1137
+ #### What the package enforces for you
1138
+
1139
+ None of this is configurable, and most of it is invisible until it bites:
1140
+
1141
+ | | |
1142
+ |---|---|
1143
+ | Code | 6 digits, HMAC-SHA256 hashed at rest, never logged |
1144
+ | Expiry | 15 minutes |
1145
+ | Attempts | **3**, then the code is destroyed and a new one must be requested |
1146
+ | Per-user cooldown | 60 seconds, tracked on `passwordResetSentAt` |
1147
+ | Per-IP limit | 5 per hour, checked **before** the user lookup |
1148
+ | On success | **every refresh token for that user is revoked** — all devices are signed out |
1149
+ | Comparison | constant-time |
1150
+
1151
+ The IP limit runs before the lookup deliberately: checking it afterwards would
1152
+ make a request for a non-existent address measurably faster than one for a real
1153
+ address, which is the enumeration leak the generic message exists to prevent.
1154
+
1155
+ #### The response never tells you what happened
1156
+
1157
+ `requestPasswordReset` returns the same success payload whether the address does
1158
+ not exist, belongs to a social-login account, or was actually sent a code. That
1159
+ is deliberate — the mutation is reachable unauthenticated, so any distinguishable
1160
+ result is an oracle for whether an address is registered.
1161
+
1162
+ If you need to know, read your `IAuthLogger`. A skip is reported as
1163
+ `PASSWORD_RESET_REQUESTED` with `result: 'SKIPPED_SOCIAL_ONLY'` and the user ID.
1164
+ An operator tool that creates accounts and invites by reset should assert on that
1165
+ event, not on the mutation's return value.
1166
+
1167
+ #### Accounts with no password
1168
+
1169
+ An account is refused only if it has an actual social identity — `googleId`,
1170
+ `facebookId` or `appleId`. A password-less account with none of those, which is
1171
+ how an operator-provisioned account starts, receives a code and can redeem it.
1172
+ This is the documented "invite by password reset" flow.
1173
+
1174
+ **This changed in 0.12.0.** Before then the test was `passwordHash == null`, so
1175
+ operator-created accounts were skipped silently and could never sign in. See
1176
+ [Migrating to v0.12.0](#migrating-to-v0120) for the consequence worth deciding
1177
+ on. The predicate is exported as `hasSocialIdentity(user)` if you want the same
1178
+ test in your own code.
1179
+
1180
+ #### Token mode
1181
+
1182
+ With `features.verificationMode: 'token'` the email carries a link rather than a
1183
+ code, and `performResetPassword` takes the token lifted from that link in place
1184
+ of the 6-digit code. Everything above still applies. See
1185
+ [Verification Modes](#verification-modes).
1186
+
862
1187
  ### Password Policy
863
1188
 
864
1189
  ```typescript
@@ -1020,6 +1345,8 @@ These sit beside `useFactory`, not in the object it returns.
1020
1345
  | `bruteForce.ipRateLimit` | `{ maxAttempts, windowMs }` | -- | IP rate-limit policy for `checkIpRateLimit`. When set, `rateLimiterInstance` MUST also be provided explicitly (boot fails with `InvalidAuthConfigException` otherwise). See [IP Rate Limiting](#ip-rate-limiting). |
1021
1346
  | `realm.skip` | `(path, request) => boolean` | -- | Requests that need no realm, such as health checks and webhooks. Read only with `realmExtractorInstance`. See [Realm-Based Identity Isolation](#realm-based-identity-isolation) |
1022
1347
  | `refreshGracePeriodSeconds` | `number` | `10` | How long a retried refresh gets the same token pair. `0` turns retries off. See [Refresh Retries](#refresh-retries) |
1348
+ | `apiKey.headerName` | `string` | -- | A header carrying the raw API key, e.g. `'X-API-Key'`, read before `Authorization`. See [API Key Authentication](#api-key-authentication) |
1349
+ | `apiKey.prefix` | `string` | -- | The prefix every API key you issue starts with, e.g. `'ait_'`. Makes an unknown key unambiguous. See [API Key Authentication](#api-key-authentication) |
1023
1350
 
1024
1351
  ### Feature Flags (`features`)
1025
1352
 
@@ -1094,7 +1421,40 @@ When `email` is provided, it takes precedence over `emailServiceInstance`.
1094
1421
  |--------|------|---------|-------------|
1095
1422
  | `tokenLength` | `number` | `64` | Token length in bytes (token mode) |
1096
1423
  | `tokenExpiresInMinutes` | `number` | `60` | Token expiration (token mode) |
1097
- | `baseUrl` | `string` | -- | Absolute http(s) base URL for verification/reset links. **Required when `verificationMode` is `'token'`** (validated at boot); optional in code mode |
1424
+ | `baseUrl` | `string \| VerificationBaseUrlResolver` | — | Absolute http(s) base URL for verification/reset links, or a resolver called with the request's realm. **Required when `verificationMode` is `'token'`** (validated at boot); optional in code mode |
1425
+
1426
+ ### SendGrid Options (`sendgrid`)
1427
+
1428
+ Read only by the bundled `SendGridEmailService`. A custom `IEmailService` ignores
1429
+ this block entirely.
1430
+
1431
+ | Option | Type | Required | Description |
1432
+ |--------|------|----------|-------------|
1433
+ | `apiKey` | `string` | yes | SendGrid API key |
1434
+ | `fromEmail` | `string` | yes | Verified sender address |
1435
+ | `fromName` | `string` | — | Display name on the From header |
1436
+
1437
+ ### Twilio Options (`twilio`)
1438
+
1439
+ Read only by the bundled `TwilioSmsService`. A custom `ISmsService` ignores this
1440
+ block entirely.
1441
+
1442
+ | Option | Type | Required | Description |
1443
+ |--------|------|----------|-------------|
1444
+ | `accountSid` | `string` | yes | Twilio account SID |
1445
+ | `authToken` | `string` | yes | Twilio auth token |
1446
+ | `phoneNumber` | `string` | yes | Sending number, E.164 |
1447
+
1448
+ ### Biometric Options (`biometric`)
1449
+
1450
+ Read only when `biometricRepositoryInstance` is provided. Passing this block
1451
+ without it is reported at boot, not refused.
1452
+
1453
+ | Option | Type | Default | Description |
1454
+ |--------|------|---------|-------------|
1455
+ | `verifiers` | `IBiometricVerifier[]` | `[new Es256DeviceKeyVerifier()]` | One per credential algorithm. Two claiming the same algorithm is refused at boot — resolution would depend on array order |
1456
+ | `challengeExpirySeconds` | `number` | `60` | Short on purpose: it bounds replay |
1457
+ | `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` |
1098
1458
 
1099
1459
  ### Optional Instance Options
1100
1460
 
@@ -1126,6 +1486,7 @@ When `email` is provided, it takes precedence over `emailServiceInstance`.
1126
1486
  | `@PublicEndpoint()` | Method/Class | Skip authentication + tenant resolution (combines `@Public()` + `@SkipTenant()`) |
1127
1487
  | `@SkipTenant()` | Method/Class | Skip tenant resolution |
1128
1488
  | `@RequirePermissions('p1', 'p2')` | Method/Class | Require specific permissions |
1489
+ | `@RequireScopes('s1', 's2')` | Method/Class | Require API key scopes, enforced by `ScopeGuard`. People are unaffected. See [API Key Authentication](#api-key-authentication) |
1129
1490
  | `@CurrentUser()` | Parameter | Inject authenticated user |
1130
1491
  | `@CurrentTenant()` | Parameter | Inject resolved tenant context |
1131
1492
  | `@CurrentRealm()` | Parameter | Inject resolved realm from request context |
@@ -1139,6 +1500,7 @@ When `email` is provided, it takes precedence over `emailServiceInstance`.
1139
1500
  | `CsrfGuard` | CSRF header validation for cookie auth |
1140
1501
  | `TenantGuard` | Multi-tenant context resolution |
1141
1502
  | `PermissionGuard` | Permission checking against tenant context |
1503
+ | `ScopeGuard` | `@RequireScopes()` enforcement for API keys; register it after the authentication guard |
1142
1504
  | `JwtAuthGuard` | JWT-only guard for GraphQL and HTTP routes (prefer `createAuthGuard` for several strategies or `@Public()`) |
1143
1505
 
1144
1506
  ### Recommended Guard Chains
@@ -1149,8 +1511,9 @@ When realm support is enabled, `RealmMiddleware` runs before all guards (as Nest
1149
1511
  // JWT only
1150
1512
  { provide: APP_GUARD, useClass: createAuthGuard(['jwt'], { allowPublic: true }) }
1151
1513
 
1152
- // JWT + API keys
1153
- { provide: APP_GUARD, useClass: createAuthGuard(['jwt', 'api-key'], { allowPublic: true }) }
1514
+ // JWT + API keys, with scopes enforced on the keys
1515
+ { provide: APP_GUARD, useClass: createAuthGuard(['jwt', 'api-key'], { allowPublic: true }) },
1516
+ { provide: APP_GUARD, useClass: ScopeGuard },
1154
1517
 
1155
1518
  // Full stack with cookie auth + multi-tenancy
1156
1519
  { provide: APP_GUARD, useClass: CsrfGuard },
@@ -1231,8 +1594,53 @@ export class CustomGuard implements CanActivate {
1231
1594
  - **`__Host-` cookie prefix** support for enhanced cookie security
1232
1595
  - **Separate HMAC secrets** for refresh tokens, verification codes, and OAuth state
1233
1596
  - **Realm-based identity isolation** with JWT realm claim validation, realm-scoped rate limiting and lockout, and auth flows that refuse a request without a realm
1597
+ - **Pinned JWT algorithms** -- the package's own `jwt` strategy verifies `HS256` only, and `createExternalJwtStrategy` requires an explicit `algorithms` list from one family (see [External JWTs](#external-jwts))
1598
+ - **API keys with scopes and expiry**, refused hard when they carry your prefix and match no key, so no other strategy accepts them
1234
1599
  - **No raw personal data in package logs** — log lines use the user ID or a salted hash (`emailHash=`, `ipHash=`, under `AUTH_IP_HASH_SALT` or `jwtSecret`), phone numbers keep only their last two digits, and the default `ConsoleAuthLogger` redacts security-event metadata. A custom `authLoggerInstance` receives the raw fields; pass them through `redactSecurityEventMetadata` to store them redacted.
1235
1600
 
1601
+ ## Upgrading from 0.9.x
1602
+
1603
+ Four releases separate 0.9 from 0.14 and each has its own note below. If you are
1604
+ jumping the whole way, this is the order things will bite, and the short answer
1605
+ for each.
1606
+
1607
+ | Release | What you have to do |
1608
+ |---|---|
1609
+ | **0.10.0** | Usually nothing. If you relied on `['api-key','jwt']` rejecting JWTs, it no longer does — an unknown key now fails softly so the next strategy runs |
1610
+ | **0.11.0** | `getRequestFromContext` can return `undefined`; TypeScript flags every call that assumed otherwise. If you use subscriptions with cookie auth, set `csrf.webSocket` |
1611
+ | **0.12.0** | The `jwt` strategy pins HS256 — check anything minting staff tokens elsewhere. Security events are logged once instead of twice, so counts built on them halve. Password reset now reaches password-less accounts with no social identity |
1612
+ | **0.13.0** | Nothing — and it was never published separately; its changes ship inside 0.14.0 |
1613
+ | **0.14.0** | Biometric authentication is rebuilt and breaking. If you never wired `biometricRepositoryInstance`, nothing changes. If you did, read the security note in the changelog first |
1614
+
1615
+ Two things that are easy to miss because nothing errors:
1616
+
1617
+ - **Security-event counts.** 0.12.0 stopped double-logging `SIGNUP_SUCCESS`,
1618
+ `LOGIN_SUCCESS` and `LOGOUT_SUCCESS`. Dashboards built before it were reading
1619
+ double and will step down on upgrade rather than when you fix the data.
1620
+ - **`verification.baseUrl`.** If you run realms and serve more than one frontend,
1621
+ it accepts a resolver from 0.13.0. Before that, every realm got the same host.
1622
+
1623
+ Take them in order rather than jumping straight to 0.14.0 — each note assumes the
1624
+ one before it.
1625
+
1626
+ ## Migrating to v0.12.0
1627
+
1628
+ **Password reset now reaches accounts that have no password and no social login.** The guard on `requestPasswordReset` and `resetPassword` tested `passwordHash == null` and treated it as "this user signed in with Google". That is also how an operator-provisioned account starts, so an account created by an admin CLI was skipped silently — the request returned the same success message as a real send, and the reset would have been refused even if a code had arrived. Both guards now test for an actual social identity (`googleId`, `facebookId` or `appleId`), so a social-only account behaves exactly as before, and a password-less account with no social identity receives a reset code and can redeem it.
1629
+
1630
+ Two consequences worth deciding on rather than discovering. A half-finished signup row with no password and no social identity can now be claimed by whoever controls the address — previously it was unreachable, which is not the same as safe. And if you wrote a placeholder password hash to work around the old behaviour, you can drop it; `hasSocialIdentity` is exported if you want the same predicate.
1631
+
1632
+ The public response is unchanged in both cases. `requestPasswordReset` still returns the same generic message whether it sent, skipped or found nothing, because it is reachable unauthenticated and anything else would be an enumeration oracle. A skip is reported to your `IAuthLogger` instead, as `PASSWORD_RESET_REQUESTED` with `result: 'SKIPPED_SOCIAL_ONLY'`.
1633
+
1634
+ **`verification.baseUrl` accepts a resolver.** Purely additive — a string behaves exactly as before. See [`baseUrl` per realm](#one-api-several-brands-baseurl-per-realm).
1635
+
1636
+ **The `jwt` strategy now pins `HS256`.** That is the algorithm `JwtModule` signs with, so every token this package issues keeps working. A token signed with `jwtSecret` under HS384 or HS512 -- which jsonwebtoken accepted while nothing was pinned -- is now rejected. If another system mints tokens for the `jwt` strategy, check that it signs HS256, or give it its own strategy with [`createExternalJwtStrategy`](#external-jwts).
1637
+
1638
+ **Each security event is logged once.** `BaseAuthResolver` logged `SIGNUP_SUCCESS`, `LOGIN_SUCCESS` and `LOGOUT_SUCCESS` on top of `AuthService`, so an `IAuthLogger` writing to an audit table stored two rows per signup, login and logout. The service's copy is the one that remains: it also covers flows that never reach the resolver. Counts built on those events halve, and `LOGOUT_SUCCESS` metadata is now `{ userId }` -- the resolver's copy also carried `email`. `SIGNUP_ATTEMPT` and `LOGOUT_ALL`, which only the resolver logs, are unchanged.
1639
+
1640
+ **A signup refused by `features.preventEnumerationOnSignup` no longer logs `SIGNUP_SUCCESS`.** It used to log one, with the synthetic response's random user ID, for an account that was never created.
1641
+
1642
+ **API keys.** Nothing changes until you set `apiKey.prefix` or `apiKey.headerName`, or store `scopes` / `expiresAt`. `ApiKeyStrategy`'s constructor takes the `apiKey` options as an optional second argument, which matters only if you construct it yourself.
1643
+
1236
1644
  ## Migrating to v0.11.0
1237
1645
 
1238
1646
  **`getRequestFromContext` may return `undefined`.** It now also finds a `graphql-ws` subscription's upgrade request, and returns `undefined` where there is no request at all. TypeScript flags each call that assumes a request. In a guard that cannot decide without one, use `requireRequestFromContext`.
@@ -14,6 +14,7 @@ import { ITenantRepository } from './interfaces/tenant-repository.interface';
14
14
  import { ITenantExtractor } from './interfaces/tenant-extractor.interface';
15
15
  import { IRealmExtractor } from './interfaces/realm-extractor.interface';
16
16
  import { IResourcePermissionRepository } from './interfaces/resource-permission-repository.interface';
17
+ import { IBiometricVerifier } from './interfaces/biometric-verifier.interface';
17
18
  import { IJwtPayloadFactory } from './interfaces/jwt-payload-factory.interface';
18
19
  import { IApiKeyRepository } from './interfaces/api-key-repository.interface';
19
20
  import { PasswordPolicyConfig } from './interfaces/password-policy-config.interface';
@@ -56,6 +57,10 @@ export interface AuthModuleOptions {
56
57
  resourcePermissionRepositoryInstance?: IResourcePermissionRepository;
57
58
  jwtPayloadFactoryInstance?: IJwtPayloadFactory;
58
59
  apiKeyRepositoryInstance?: IApiKeyRepository;
60
+ apiKey?: {
61
+ headerName?: string;
62
+ prefix?: string;
63
+ };
59
64
  jwtValidation?: 'full' | 'payload-only';
60
65
  isUserActive?: (user: IAuthUser) => boolean;
61
66
  bcryptRounds?: number;
@@ -117,12 +122,21 @@ export interface AuthModuleOptions {
117
122
  branding?: EmailBrandingConfig;
118
123
  templateRenderer?: IEmailTemplateRenderer;
119
124
  };
125
+ biometric?: {
126
+ verifiers?: IBiometricVerifier[];
127
+ challengeExpirySeconds?: number;
128
+ challengeRateLimit?: {
129
+ maxAttempts: number;
130
+ windowMs: number;
131
+ };
132
+ };
120
133
  verification?: {
121
134
  tokenLength?: number;
122
135
  tokenExpiresInMinutes?: number;
123
- baseUrl?: string;
136
+ baseUrl?: string | VerificationBaseUrlResolver;
124
137
  };
125
138
  }
139
+ export type VerificationBaseUrlResolver = (realm?: string) => string;
126
140
  export interface AuthModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
127
141
  useFactory: (...args: any[]) => Promise<AuthModuleOptions> | AuthModuleOptions;
128
142
  inject?: any[];
@@ -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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"}