@ambushsoftworks/nestjs-auth-graphql 0.9.1 → 0.11.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 (91) hide show
  1. package/CHANGELOG.md +231 -0
  2. package/README.md +164 -8
  3. package/dist/auth.module.d.ts +10 -0
  4. package/dist/auth.module.d.ts.map +1 -1
  5. package/dist/auth.module.js +69 -2
  6. package/dist/auth.module.js.map +1 -1
  7. package/dist/exceptions/oauth.exceptions.d.ts +4 -1
  8. package/dist/exceptions/oauth.exceptions.d.ts.map +1 -1
  9. package/dist/exceptions/oauth.exceptions.js +12 -1
  10. package/dist/exceptions/oauth.exceptions.js.map +1 -1
  11. package/dist/guards/create-auth-guard.d.ts.map +1 -1
  12. package/dist/guards/create-auth-guard.js +3 -6
  13. package/dist/guards/create-auth-guard.js.map +1 -1
  14. package/dist/guards/csrf.guard.d.ts +2 -0
  15. package/dist/guards/csrf.guard.d.ts.map +1 -1
  16. package/dist/guards/csrf.guard.js +26 -5
  17. package/dist/guards/csrf.guard.js.map +1 -1
  18. package/dist/guards/jwt-auth.guard.d.ts +2 -1
  19. package/dist/guards/jwt-auth.guard.d.ts.map +1 -1
  20. package/dist/guards/jwt-auth.guard.js +6 -3
  21. package/dist/guards/jwt-auth.guard.js.map +1 -1
  22. package/dist/guards/permission.guard.js +2 -2
  23. package/dist/guards/permission.guard.js.map +1 -1
  24. package/dist/guards/tenant.guard.d.ts.map +1 -1
  25. package/dist/guards/tenant.guard.js +3 -0
  26. package/dist/guards/tenant.guard.js.map +1 -1
  27. package/dist/index.d.ts +3 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +3 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/interfaces/refresh-retry-cache.interface.d.ts +6 -0
  32. package/dist/interfaces/refresh-retry-cache.interface.d.ts.map +1 -0
  33. package/dist/interfaces/refresh-retry-cache.interface.js +3 -0
  34. package/dist/interfaces/refresh-retry-cache.interface.js.map +1 -0
  35. package/dist/interfaces/refresh-token-repository.interface.d.ts.map +1 -1
  36. package/dist/middleware/realm.middleware.d.ts +7 -2
  37. package/dist/middleware/realm.middleware.d.ts.map +1 -1
  38. package/dist/middleware/realm.middleware.js +60 -14
  39. package/dist/middleware/realm.middleware.js.map +1 -1
  40. package/dist/resolvers/base-auth.resolver.d.ts.map +1 -1
  41. package/dist/resolvers/base-auth.resolver.js +2 -1
  42. package/dist/resolvers/base-auth.resolver.js.map +1 -1
  43. package/dist/resolvers/oauth.controller.d.ts.map +1 -1
  44. package/dist/resolvers/oauth.controller.js +27 -17
  45. package/dist/resolvers/oauth.controller.js.map +1 -1
  46. package/dist/resolvers/rest-error.interceptor.d.ts +7 -0
  47. package/dist/resolvers/rest-error.interceptor.d.ts.map +1 -0
  48. package/dist/resolvers/rest-error.interceptor.js +36 -0
  49. package/dist/resolvers/rest-error.interceptor.js.map +1 -0
  50. package/dist/services/auth.service.d.ts +2 -3
  51. package/dist/services/auth.service.d.ts.map +1 -1
  52. package/dist/services/auth.service.js +15 -10
  53. package/dist/services/auth.service.js.map +1 -1
  54. package/dist/services/in-memory-refresh-retry-cache.d.ts +11 -0
  55. package/dist/services/in-memory-refresh-retry-cache.d.ts.map +1 -0
  56. package/dist/services/in-memory-refresh-retry-cache.js +45 -0
  57. package/dist/services/in-memory-refresh-retry-cache.js.map +1 -0
  58. package/dist/services/refresh-token.service.d.ts +13 -14
  59. package/dist/services/refresh-token.service.d.ts.map +1 -1
  60. package/dist/services/refresh-token.service.js +112 -33
  61. package/dist/services/refresh-token.service.js.map +1 -1
  62. package/dist/strategies/api-key.strategy.d.ts.map +1 -1
  63. package/dist/strategies/api-key.strategy.js +1 -1
  64. package/dist/strategies/api-key.strategy.js.map +1 -1
  65. package/dist/strategies/jwt.strategy.d.ts +3 -1
  66. package/dist/strategies/jwt.strategy.d.ts.map +1 -1
  67. package/dist/strategies/jwt.strategy.js +15 -11
  68. package/dist/strategies/jwt.strategy.js.map +1 -1
  69. package/dist/strategies/noop-facebook.strategy.d.ts.map +1 -1
  70. package/dist/strategies/noop-facebook.strategy.js +2 -1
  71. package/dist/strategies/noop-facebook.strategy.js.map +1 -1
  72. package/dist/strategies/noop-google.strategy.d.ts.map +1 -1
  73. package/dist/strategies/noop-google.strategy.js +2 -1
  74. package/dist/strategies/noop-google.strategy.js.map +1 -1
  75. package/dist/test-utils/execution-contexts.d.ts +7 -0
  76. package/dist/test-utils/execution-contexts.d.ts.map +1 -0
  77. package/dist/test-utils/execution-contexts.js +41 -0
  78. package/dist/test-utils/execution-contexts.js.map +1 -0
  79. package/dist/utils/cookies.d.ts +2 -0
  80. package/dist/utils/cookies.d.ts.map +1 -0
  81. package/dist/utils/cookies.js +34 -0
  82. package/dist/utils/cookies.js.map +1 -0
  83. package/dist/utils/execution-context.d.ts +3 -1
  84. package/dist/utils/execution-context.d.ts.map +1 -1
  85. package/dist/utils/execution-context.js +39 -4
  86. package/dist/utils/execution-context.js.map +1 -1
  87. package/dist/utils/request-realm.d.ts +2 -0
  88. package/dist/utils/request-realm.d.ts.map +1 -0
  89. package/dist/utils/request-realm.js +12 -0
  90. package/dist/utils/request-realm.js.map +1 -0
  91. package/package.json +13 -4
package/CHANGELOG.md CHANGED
@@ -27,6 +27,237 @@ 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.11.0] - 2026-09-15
31
+
32
+ Ambush Desk asked for two things: refresh retries that survive a second API
33
+ instance, and guards that work on GraphQL subscriptions. Checking the first one
34
+ turned up a retry bug that had been there since the first release. See
35
+ **Fixed**.
36
+
37
+ ### Fixed
38
+ - **Guards failed on GraphQL subscriptions over `graphql-ws`.** Guards read
39
+ `context.req`, which a subscription does not have. With `GraphQLModule`'s
40
+ `subscriptions: { 'graphql-ws': true }`, Nest puts graphql-ws's connection
41
+ object there instead. With an app's own `useServer`, there is no `req` at all.
42
+ Run over a real `graphql-ws` client on 0.10.0, the guard chain
43
+ `CsrfGuard` → `createAuthGuard(['jwt'])` → `TenantGuard` → `PermissionGuard`
44
+ refused every subscription:
45
+ - with `GraphQLModule` subscriptions, `CsrfGuard` answered `CSRF validation failed`
46
+ - with an own server, it threw `TypeError`s: `Cannot read properties of
47
+ undefined (reading 'headers')` with a context function, `(reading 'req')`
48
+ without one
49
+
50
+ Guards now read the WebSocket upgrade request. Authentication, realm, tenant
51
+ and permission checks all work on subscriptions, and with no request to read,
52
+ guards answer 401 or 403. Reported by Ambush Desk; Ariadne had been working
53
+ around it with a subclass.
54
+ - **A retried token refresh was always rejected when the repository deletes
55
+ used tokens.** Refresh deletes the token it used and keeps the result for 10
56
+ seconds, so that a client that lost the response can retry. The retry then
57
+ looked up the used token to find the user, found nothing, and answered
58
+ `401 Invalid refresh token`. That covers every `IRefreshTokenRepository` whose
59
+ `delete` removes the row, which is what the method is for. The lookup has been
60
+ there since `v0.1.3`. The kept result now carries the user ID, and the retry
61
+ still re-checks account status. Reproduced on 0.10.0 before the fix, with a
62
+ repository that deletes.
63
+ - **A retry arriving between deleting the used token and keeping the result was
64
+ rejected.** The result is now kept first.
65
+
66
+ ### Added
67
+ - **`csrf.webSocket: 'reject' | 'skip'`**, default `'reject'`. Browsers cannot
68
+ send the CSRF header on a WebSocket, so this decides for cookie-authenticated
69
+ subscriptions: 403, or allow. `'skip'` is safe only with an `Origin` check
70
+ when the socket connects. A subscription whose upgrade request carries an
71
+ `Authorization` header is allowed either way. Any other value fails boot.
72
+ Requested by Ambush Desk.
73
+ - **The realm on subscriptions.** `RealmMiddleware` never sees a WebSocket
74
+ upgrade, so `JwtStrategy` resolves the realm from the upgrade request itself,
75
+ once per connection, with the same `realm.skip` and extractor rules. A realm
76
+ the app sets itself (in `onConnect`, say) is kept. Requested by Ambush Desk.
77
+ - **`isWebSocketContext(context)`, `requireRequestFromContext(context)` and
78
+ `readCookie(request, name)`**, exported. `readCookie` falls back to parsing
79
+ the `Cookie` header, which is all an upgrade request has.
80
+ - **`refreshRetryCacheInstance?: IRefreshRetryCache`.** A retry that reached a
81
+ different instance than the first refresh got `401` and a
82
+ `TOKEN_REUSE_DETECTED` event, because the retry cache lived in one process.
83
+ Requested by Ambush Desk.
84
+ - Implement `get`, `set(key, value, ttlMs)` and `delete` over a store the
85
+ instances share. The interface's JSDoc has a Postgres example.
86
+ - Entries hold live tokens, so for any store but the in-memory one they are
87
+ AES-256-GCM encrypted with a key derived from `encryptionKey`, which then
88
+ becomes required and must match on every instance.
89
+ - The package enforces expiry itself, and treats store errors as a miss.
90
+ - **`refreshGracePeriodSeconds`**, default 10. `0` turns retries off. Requested
91
+ by Ambush Desk.
92
+ - **`InMemoryRefreshRetryCache`**, the default, exported so a single-instance app
93
+ can pass it explicitly.
94
+ - **Boot warnings for in-memory defaults** that only work within one instance:
95
+ `rateLimiterInstance` (password-reset throttling) and
96
+ `refreshRetryCacheInstance`. Pass `new InMemoryRateLimiterService()` and
97
+ `new InMemoryRefreshRetryCache()` to confirm a single instance and silence
98
+ them. Requested by Ambush Desk.
99
+
100
+ ### Changed
101
+ - **`getRequestFromContext` returns `Record<string, any> | undefined`.** It finds a
102
+ subscription's upgrade request, and returns `undefined` when a GraphQL context
103
+ holds no request. It did before too, while typed as never doing so. TypeScript
104
+ now flags call sites that assume a request.
105
+ - **Cookie auth no longer requires cookie-parser.** The JWT cookie extractor and
106
+ `readRefreshTokenFromCookie` fall back to the `Cookie` header.
107
+ - **`CsrfGuard` checks `exemptOperations` before reading any header**, and
108
+ answers 403 rather than throwing when a GraphQL operation's context holds no
109
+ request. HTTP outcomes are unchanged.
110
+ - **`RefreshTokenService`'s retry cache methods are async and take the user ID:**
111
+ - `cacheRefreshResult(usedTokenHash, { userId, accessToken, refreshToken })`
112
+ - `getCachedRefreshResult(usedTokenHash)`, which resolves to that shape or `null`
113
+ - `invalidateCachedRefresh(usedTokenHash)`
114
+
115
+ The class no longer runs a cleanup timer, and `onModuleDestroy` is gone. This
116
+ only affects code that calls these methods directly or subclasses the service.
117
+ Implement `IRefreshRetryCache` instead.
118
+
119
+ ### Documentation
120
+ - **CLAUDE.md described a `gracePeriodSeconds` option that never existed**, and a
121
+ Redis subclass of `RefreshTokenService` that could not work. It overrode the
122
+ synchronous cache methods with async ones, and the truthy Promise would have
123
+ sent every refresh down the cached branch. Both are replaced by the port's real
124
+ design.
125
+ - README: **Refresh Retries**, **GraphQL Subscriptions**, **Migrating to
126
+ v0.11.0**, and rows for the new options and utilities.
127
+
128
+ ### Testing
129
+ - **End-to-end subscriptions.** The suite drives real `graphql-ws` clients
130
+ against three server setups on both NestJS majors: `GraphQLModule`-managed, an
131
+ own `useServer` with a context, and one without. Against each, it checks
132
+ delivery, a missing cookie, a wrong realm, a missing permission, another
133
+ tenant, CSRF `'reject'` and `'skip'`, and a bearer token on the upgrade.
134
+ - **Refresh retries end to end:**
135
+ - a retry gets the same pair
136
+ - two instances sharing a store
137
+ - without a shared store: `TOKEN_REUSE_DETECTED`
138
+ - after the grace period: 401
139
+ - a user suspended between the refresh and its retry is refused
140
+
141
+ ## [0.10.0] - 2026-09-15
142
+
143
+ Ambush Desk, a new consumer on NestJS 11, asked for routes that need no realm, a
144
+ way to leave the OAuth REST routes unmounted, and CI on NestJS 11. Building those
145
+ turned up defects on the OAuth REST routes that affect every app mounting them
146
+ today. See **Fixed** first.
147
+
148
+ Behaviour changes, so the minor version moves. See **Migrating to v0.10.0** in
149
+ the README.
150
+
151
+ ### Fixed
152
+ - **The OAuth REST routes answered 500 for four ordinary failures.** On
153
+ `POST /auth/google/token` and `POST /auth/facebook/token`:
154
+
155
+ | Situation | Before | Now |
156
+ |---|---|---|
157
+ | Provider not configured | 500 | 404 `OAUTH_PROVIDER_NOT_CONFIGURED`, with `provider` |
158
+ | Account locked | 500 | 403 `ACCOUNT_LOCKED`, with `remainingLockoutTime` |
159
+ | Account suspended or deleted | 500 | 403 `ACCOUNT_INACTIVE` |
160
+ | Client IP over `bruteForce.ipRateLimit` | 500 | 429 `RATE_LIMIT_EXCEEDED` |
161
+
162
+ The no-op strategies and the controller's lockout and rate-limit checks threw
163
+ plain `Error`. `AccountLockedException` and `AccountInactiveException` extend
164
+ `GraphQLError`, which Nest's HTTP layer does not recognise, so since 0.9.0 a
165
+ suspended user signing in with Google also got a 500. The bodies now use the
166
+ root-level shape of the other OAuth errors: `message`, `code`, `statusCode`,
167
+ plus fields. An internal `RestErrorInterceptor` converts the GraphQL-shaped
168
+ errors on these routes only; GraphQL responses are unchanged. The lockout
169
+ message is now the one `login` uses.
170
+ - **`createAuthGuard(['api-key', 'jwt'])` rejected every JWT.** `ApiKeyStrategy`
171
+ threw for a bearer token that matched no key, and a throw stops Passport's
172
+ strategy chain, so JWT was never tried. That is the order the README and
173
+ `createAuthGuard`'s JSDoc showed. An unknown token now fails softly and the next
174
+ strategy runs, so either order accepts either credential. A key whose account is
175
+ inactive still fails with 401 `API key is inactive`. Reported by Ambush Desk.
176
+ - **The OAuth routes checked lockout and the IP rate limit, and reset failed
177
+ attempts, without the realm.** With realms enabled, `isAccountLocked`,
178
+ `getRemainingLockoutTime`, `checkIpRateLimit` and `resetFailedAttempts` were
179
+ called with no realm. Depending on how your repository treats a missing realm,
180
+ a lock could apply to the same email in another realm, and a successful sign-in
181
+ could clear another realm's failed attempts. They now receive the request's
182
+ realm, as `login` already did.
183
+
184
+ ### Added
185
+ - **`realm.skip: (path, request) => boolean`.** Requests that have no realm by
186
+ nature, such as health checks, webhooks and public downloads, pass
187
+ `RealmMiddleware` without calling the extractor, get no `_realm`, and never
188
+ answer `400 Realm required`. Requested by Ambush Desk.
189
+ - `path` is the requested path, including any global prefix and without the
190
+ query string. Do not match on `request.path` or `request.url`: Express
191
+ rewrites both to `/` inside middleware.
192
+ - Only a synchronous `true` skips. A throw or any other return value fails
193
+ closed and is logged.
194
+ - It is a predicate rather than route patterns because the same Nest route
195
+ pattern matches different paths on NestJS 10 and 11: `hooks/*` excludes
196
+ `/hooks/glitchtip/issue` on 11 but not on 10.
197
+ - With realms enabled, a `skip` that is not a function fails boot with
198
+ `InvalidAuthConfigException`. `skip` without `realmExtractorInstance` logs a
199
+ warning.
200
+ - This closes the `@SkipRealm()` follow-up for requests with no realm. A
201
+ decorator cannot work, because middleware runs before Nest resolves the
202
+ handler.
203
+ - **`oauthController: false`** on `AuthModule.forRootAsync`, beside `useFactory`,
204
+ leaves `OAuthController` unmounted, so both routes answer 404 like any unknown
205
+ path. Defaults to `true`. Requested by Ambush Desk.
206
+ - `OAuthProviderNotConfiguredException` (404, `OAUTH_PROVIDER_NOT_CONFIGURED`),
207
+ thrown by the no-op strategies.
208
+ - `AuthService.realmsEnabled`.
209
+
210
+ ### Changed
211
+ - **Realm-scoped entry points refuse a request without a realm.** With realms
212
+ enabled, `BaseAuthResolver` flows (through `getRealmFromContext`) and the OAuth
213
+ routes answer `400 Realm required` when the request has no realm, instead of
214
+ running with `realm` undefined, which many repositories read as "any realm".
215
+ Before `realm.skip` the middleware ruled this out over HTTP; now it also
216
+ contains a `skip` predicate that matches more than intended. Code that calls
217
+ `perform*` methods without the GraphQL context gets the 400 too when realms are
218
+ enabled.
219
+ - **The OAuth routes' IP rate-limit keys include the realm**
220
+ (`auth:ipRate:<realm>:<ipHash>`, as for `login`), so existing counts for those
221
+ routes start again after upgrading.
222
+ - With `['api-key']` alone, an unknown key's 401 now carries the guard's generic
223
+ `Unauthorized` message instead of `Invalid API key`. That also stops confirming
224
+ to the caller that the token was checked as an API key.
225
+ - `JwtAuthGuard` reads the request through `getRequestFromContext`, as
226
+ `createAuthGuard` does, instead of through `GqlExecutionContext`. There is no
227
+ behaviour change: the old lookup also returned the HTTP request on HTTP routes,
228
+ checked on NestJS 10 and 11.
229
+
230
+ ### Documentation
231
+ - README: routes without a realm, `oauthController`, the OAuth routes' error
232
+ table, guard order for API keys and JWTs, a **Module Options** table, NestJS 10
233
+ and 11 support, and **Migrating to v0.10.0**. The OAuth section no longer calls
234
+ the routes callback routes; they exchange tokens.
235
+ - `IRefreshTokenRepository` documents that entities returned by
236
+ `findByHashedToken` must carry `id`, `userId` and `createdAt`, and that refresh
237
+ measures expiry from `createdAt`. `create` is not given `createdAt`, so a store
238
+ with no default for it fails on refresh. Found by the new end-to-end suite.
239
+
240
+ ### Testing
241
+ - **CI runs on NestJS 11.** A `test:nest11` job runs the build, unit tests and
242
+ end-to-end suite on NestJS 11, `@nestjs/graphql` 13, Apollo Server 5 and
243
+ Express 5, beside the NestJS 10 job. Run locally before release: 982 unit tests
244
+ and 29 end-to-end tests pass on NestJS 11.2.5, `@nestjs/graphql` 13.4.5, Apollo
245
+ Server 5.5.1 and Express 5.2.1, with no source change for NestJS 11. On Express,
246
+ `@nestjs/apollo` 13 also needs `@as-integrations/express5`. Requested by Ambush
247
+ Desk.
248
+ - **An end-to-end suite** (`npm run test:e2e`, in `test/e2e`) boots a real HTTP
249
+ and GraphQL (Apollo) application against the built package, with in-memory
250
+ repositories. It covers:
251
+ - realm skipping and rejection
252
+ - the OAuth routes mounted, unmounted, and failing with each status above
253
+ - `createAuthGuard` with API keys and JWTs in both orders, on HTTP and in a
254
+ resolver
255
+ - `JwtAuthGuard` on HTTP
256
+ - login and refresh through a `BaseAuthResolver` subclass
257
+
258
+ Each fix above was checked by reintroducing the defect and watching a unit or
259
+ end-to-end test fail.
260
+
30
261
  ## [0.9.1] - 2026-09-14
31
262
 
32
263
  Documentation only — no code changes. npm shows the README of the latest
package/README.md CHANGED
@@ -20,10 +20,12 @@ Production-grade authentication module for NestJS GraphQL + REST APIs. JWT, cook
20
20
  - [Password Policy](#password-policy)
21
21
  - [Lifecycle Hooks](#lifecycle-hooks)
22
22
  - [Account Status](#account-status)
23
+ - [Refresh Retries](#refresh-retries)
23
24
  - [JWT Validation Modes](#jwt-validation-modes)
24
25
  - [JWT Payload Factory](#jwt-payload-factory)
25
26
  - [Configuration Reference](#configuration-reference)
26
27
  - [Required Options](#required-options)
28
+ - [Module Options](#module-options-forrootasync)
27
29
  - [Common Options](#common-options)
28
30
  - [Feature Flags](#feature-flags-features)
29
31
  - [Security Secrets](#security-secrets)
@@ -34,8 +36,11 @@ Production-grade authentication module for NestJS GraphQL + REST APIs. JWT, cook
34
36
  - [Optional Instance Options](#optional-instance-options)
35
37
  - [Decorators](#decorators)
36
38
  - [Guards](#guards)
39
+ - [GraphQL Subscriptions](#graphql-subscriptions)
37
40
  - [Utilities](#utilities)
38
41
  - [Security Features](#security-features)
42
+ - [Migrating to v0.11.0](#migrating-to-v0110)
43
+ - [Migrating to v0.10.0](#migrating-to-v0100)
39
44
  - [Migrating to v0.9.0](#migrating-to-v090)
40
45
  - [License](#license)
41
46
 
@@ -65,6 +70,8 @@ npm install @nestjs/common @nestjs/core @nestjs/graphql @nestjs/jwt @nestjs/pass
65
70
 
66
71
  `resend` is an optional peer dependency -- install it only if using the Resend email sender.
67
72
 
73
+ 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.
74
+
68
75
  ## Quick Start
69
76
 
70
77
  Minimal setup: JWT authentication with email/password login.
@@ -469,6 +476,29 @@ AuthModule.forRootAsync({
469
476
 
470
477
  `RealmMiddleware` is automatically registered by `AuthModule` — no manual middleware registration needed. When a `realmExtractorInstance` is provided, the middleware calls `extractor.extractRealm(request)` on every request before any guards run. If the extractor returns `null`, the request is rejected with `400 Bad Request` (strict mode).
471
478
 
479
+ **Routes without a realm.** Health checks, inbound webhooks and public downloads have no realm by nature. Match them with `realm.skip`, and the middleware lets them through without calling the extractor:
480
+
481
+ ```typescript
482
+ AuthModule.forRootAsync({
483
+ // ...
484
+ useFactory: (usersRepo, tokenRepo, realmExtractor, config) => ({
485
+ // ...required options
486
+ realmExtractorInstance: realmExtractor,
487
+ realm: {
488
+ skip: (path) => path === '/health' || path.startsWith('/hooks/'),
489
+ },
490
+ }),
491
+ })
492
+ ```
493
+
494
+ - `path` is the path the client requested, including any global prefix and without the query string. Match on it, not on `request.path` or `request.url`: Express rewrites both to `/` inside middleware. The request itself is the second argument.
495
+ - A skipped request has no realm: `request._realm` stays undefined.
496
+ - **Skip only routes that are unauthenticated or authenticate by other means.** A JWT's realm claim cannot match a request with no realm, so `JwtStrategy` answers 401. `BaseAuthResolver` flows and the OAuth routes answer `400 Realm required` rather than run outside a realm, which also contains a predicate that matches more than you meant.
497
+ - `skip` must return a boolean synchronously. If it throws or returns anything else, such as the Promise from an `async` function, the request is not skipped and the error is logged.
498
+ - Without `realmExtractorInstance`, `realm.skip` is ignored and a warning is logged at boot. A `realm.skip` that is not a function fails boot with `InvalidAuthConfigException`.
499
+
500
+ Why a predicate rather than route patterns: the same Nest route pattern matches different paths on NestJS 10 and NestJS 11 — `hooks/*` excludes `/hooks/glitchtip/issue` on 11 but not on 10 — so a pattern list would behave differently depending on your Nest version. A `@SkipRealm()` decorator cannot work either, because middleware runs before Nest resolves the route handler.
501
+
472
502
  **Use `@CurrentRealm()` in resolvers:**
473
503
 
474
504
  ```typescript
@@ -525,7 +555,9 @@ Then use a multi-strategy guard:
525
555
  { provide: APP_GUARD, useClass: createAuthGuard(['api-key', 'jwt'], { allowPublic: true }) }
526
556
  ```
527
557
 
528
- The `ApiKeyStrategy` hashes the bearer token with SHA-256 and calls `findByKeyHash()` on your repository. API keys and JWT tokens use the same `Authorization: Bearer` header -- strategies are tried in the order specified. When no bearer token is present (e.g. cookie auth), the API key strategy gracefully falls through to the next strategy.
558
+ The `ApiKeyStrategy` hashes the bearer token with SHA-256 and calls `findByKeyHash()` on your repository. API keys and JWTs share the `Authorization: Bearer` header, and strategies are tried in the order listed. A request with no bearer token, or with one that matches no key, falls through to the next strategy, so `['api-key', 'jwt']` and `['jwt', 'api-key']` both accept either credential. A key that matches an inactive account is rejected with 401 and no other strategy runs. When every strategy fails, the guard answers 401.
559
+
560
+ Before 0.10.0 the API key strategy rejected an unknown bearer token itself, which stopped the chain: `['api-key', 'jwt']` rejected every JWT.
529
561
 
530
562
  ### Email System
531
563
 
@@ -695,7 +727,33 @@ AuthModule.forRootAsync({
695
727
  })
696
728
  ```
697
729
 
698
- The `OAuthController` is automatically registered and handles OAuth callback routes. OAuth strategies gracefully degrade to no-ops when credentials are not configured.
730
+ `OAuthController` mounts two token-exchange routes for native mobile sign-in: `POST /auth/google/token` with body `{ "idToken": "..." }`, and `POST /auth/facebook/token` with body `{ "accessToken": "..." }`. Both return `{ accessToken, refreshToken, user }`.
731
+
732
+ **Not using them?** Leave them unmounted, and they answer 404 like any unknown path:
733
+
734
+ ```typescript
735
+ AuthModule.forRootAsync({
736
+ oauthController: false, // beside useFactory, not inside it
737
+ useFactory: () => ({ /* ... */ }),
738
+ })
739
+ ```
740
+
741
+ It sits beside `useFactory` because Nest fixes a module's controllers before async options resolve. GraphQL account linking does not use these routes and keeps working.
742
+
743
+ **Errors.** The routes answer with an HTTP status and a body carrying `message`, `code` and `statusCode` at the root, plus the fields listed:
744
+
745
+ | Status | `code` | When | Other fields |
746
+ |--------|--------|------|--------------|
747
+ | 404 | `OAUTH_PROVIDER_NOT_CONFIGURED` | The provider has no credentials in this deployment | `provider` |
748
+ | 401 | `INVALID_OAUTH_TOKEN` | The provider rejected the token | `provider` |
749
+ | 400 | `OAUTH_MISSING_DATA` | The provider returned no email, or an unverified one | `provider`, `missingField`; for a new Facebook user, `fallbackToken` and `providerId` |
750
+ | 409 | `EMAIL_EXISTS_WITH_PASSWORD` | The email belongs to a password account | `email`, `linkingToken` |
751
+ | 409 | `OAUTH_ACCOUNT_ALREADY_LINKED` | The account has a different ID linked for this provider | `provider` |
752
+ | 403 | `ACCOUNT_LOCKED` | Brute-force lockout | `remainingLockoutTime` (seconds) |
753
+ | 403 | `ACCOUNT_INACTIVE` | The account is suspended or deleted | -- |
754
+ | 429 | `RATE_LIMIT_EXCEEDED` | The client IP exceeded `bruteForce.ipRateLimit` | -- |
755
+
756
+ 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.
699
757
 
700
758
  ### Brute Force Protection
701
759
 
@@ -871,6 +929,35 @@ It must be synchronous and pure: it runs on every authenticated request, against
871
929
 
872
930
  **Your repository must return inactive users.** `findById` and `findByEmail` should return suspended and soft-deleted users like any other. A repository that hides them turns `ACCOUNT_INACTIVE` into a "not found" failure, and the package can no longer tell the client why.
873
931
 
932
+ ### Refresh Retries
933
+
934
+ Refresh tokens rotate: each refresh deletes the token it used. A client that loses the response — a dropped connection, a timeout, an HTTP client that retries — sends the used token again, which looks exactly like a stolen token being replayed. For `refreshGracePeriodSeconds` (default 10) the package remembers the result and answers the retry with the same token pair. `0` turns this off.
935
+
936
+ **One instance:** nothing to do.
937
+
938
+ **More than one instance:** give every instance the same store, or a retry that reaches a different instance gets `401` and signs the user out:
939
+
940
+ ```typescript
941
+ AuthModule.forRootAsync({
942
+ inject: [PgRefreshRetryCache, PgRateLimiter, ConfigService],
943
+ useFactory: (retryCache, rateLimiter, config) => ({
944
+ // ...required options
945
+ refreshRetryCacheInstance: retryCache,
946
+ encryptionKey: config.getOrThrow('ENCRYPTION_KEY'), // required with a shared store, same on every instance
947
+ rateLimiterInstance: rateLimiter, // password-reset throttling needs sharing for the same reason
948
+ }),
949
+ })
950
+ ```
951
+
952
+ - Implement `IRefreshRetryCache` (`get`, `set(key, value, ttlMs)`, `delete`) over Redis, Postgres, or any store the instances share. Its JSDoc has a Postgres example.
953
+ - The values are AES-256-GCM ciphertext, because they hold live tokens. Boot fails with `InvalidAuthConfigException` when `encryptionKey` is missing.
954
+ - The package enforces expiry itself, so the store's TTL can be approximate.
955
+ - A store that errors costs retries, never the refresh itself.
956
+
957
+ At boot the package warns for each in-memory default in use, `rateLimiterInstance` and `refreshRetryCacheInstance`, because it cannot tell how many instances run. Pass `new InMemoryRateLimiterService()` and `new InMemoryRefreshRetryCache()` explicitly to confirm a single instance and silence them.
958
+
959
+ Before 0.11.0 a retry got `401` whenever `IRefreshTokenRepository.delete` removed the used token, even on a single instance.
960
+
874
961
  ### JWT Validation Modes
875
962
 
876
963
  - **`'full'`** (default) -- Calls `userRepository.findById()` on every request, rejecting the request if the user no longer exists or is no longer active (see [Account Status](#account-status)).
@@ -907,6 +994,17 @@ jwtPayloadFactoryInstance: {
907
994
  | `refreshTokenRepositoryInstance` | `IRefreshTokenRepository` | Token persistence |
908
995
  | `jwtSecret` | `string` | JWT signing secret |
909
996
 
997
+ ### Module Options (`forRootAsync`)
998
+
999
+ These sit beside `useFactory`, not in the object it returns.
1000
+
1001
+ | Option | Type | Default | Description |
1002
+ |--------|------|---------|-------------|
1003
+ | `useFactory` | `(...deps) => AuthModuleOptions` | -- | Returns the options in the other tables. Required |
1004
+ | `inject` | `any[]` | `[]` | Providers passed to `useFactory` |
1005
+ | `imports` | `any[]` | `[]` | Modules that export those providers |
1006
+ | `oauthController` | `boolean` | `true` | Mount the REST OAuth token routes. See [OAuth](#oauth) |
1007
+
910
1008
  ### Common Options
911
1009
 
912
1010
  | Option | Type | Default | Description |
@@ -920,6 +1018,8 @@ jwtPayloadFactoryInstance: {
920
1018
  | `passwordPolicy` | `PasswordPolicyConfig` | See [Password Policy](#password-policy) | Password strength rules |
921
1019
  | `encryptionKey` | `string` | -- | 32-byte hex string for AES-256-GCM (OAuth token encryption) |
922
1020
  | `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
+ | `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
+ | `refreshGracePeriodSeconds` | `number` | `10` | How long a retried refresh gets the same token pair. `0` turns retries off. See [Refresh Retries](#refresh-retries) |
923
1023
 
924
1024
  ### Feature Flags (`features`)
925
1025
 
@@ -975,6 +1075,7 @@ Separate HMAC secrets for security isolation. All fall back to `jwtSecret` if no
975
1075
  | `headerName` | `string` | `'X-Requested-With'` | Header to check |
976
1076
  | `requireInProduction` | `boolean` | `true` | Require CSRF header in production |
977
1077
  | `exemptOperations` | `string[]` | `[]` | GraphQL operations to skip |
1078
+ | `webSocket` | `'reject' \| 'skip'` | `'reject'` | Cookie-authenticated GraphQL subscriptions: refuse with 403, or allow. `'skip'` needs an `Origin` check when the socket connects. See [GraphQL Subscriptions](#graphql-subscriptions) |
978
1079
 
979
1080
  ### Composable Email (`email`)
980
1081
 
@@ -1012,6 +1113,7 @@ When `email` is provided, it takes precedence over `emailServiceInstance`.
1012
1113
  | `jwtPayloadFactoryInstance` | `IJwtPayloadFactory` | `DefaultJwtPayloadFactory` |
1013
1114
  | `apiKeyRepositoryInstance` | `IApiKeyRepository` | `null` |
1014
1115
  | `rateLimiterInstance` | `IRateLimiter` | `InMemoryRateLimiterService` (Note: this fallback does NOT apply when `bruteForce.ipRateLimit` is configured — boot fails with `InvalidAuthConfigException` and an explicit `rateLimiterInstance` is required. See [IP Rate Limiting](#ip-rate-limiting) above.) |
1116
+ | `refreshRetryCacheInstance` | `IRefreshRetryCache` | `InMemoryRefreshRetryCache`, which answers retries on the same instance only. A shared store requires `encryptionKey`. See [Refresh Retries](#refresh-retries) |
1015
1117
  | `realmExtractorInstance` | `IRealmExtractor` | `null` (realms disabled) |
1016
1118
 
1017
1119
  ---
@@ -1037,7 +1139,7 @@ When `email` is provided, it takes precedence over `emailServiceInstance`.
1037
1139
  | `CsrfGuard` | CSRF header validation for cookie auth |
1038
1140
  | `TenantGuard` | Multi-tenant context resolution |
1039
1141
  | `PermissionGuard` | Permission checking against tenant context |
1040
- | `JwtAuthGuard` | Basic JWT guard (prefer `createAuthGuard`) |
1142
+ | `JwtAuthGuard` | JWT-only guard for GraphQL and HTTP routes (prefer `createAuthGuard` for several strategies or `@Public()`) |
1041
1143
 
1042
1144
  ### Recommended Guard Chains
1043
1145
 
@@ -1057,13 +1159,45 @@ When realm support is enabled, `RealmMiddleware` runs before all guards (as Nest
1057
1159
  { provide: APP_GUARD, useClass: PermissionGuard },
1058
1160
  ```
1059
1161
 
1162
+ ### GraphQL Subscriptions
1163
+
1164
+ The guards also protect subscriptions over `graphql-ws`. A socket has no HTTP request, so they read the WebSocket upgrade request instead: the headers and cookies the client opened the connection with.
1165
+
1166
+ | Guard | On a subscription |
1167
+ |-------|-------------------|
1168
+ | `createAuthGuard`, `JwtAuthGuard` | Authenticates from the upgrade request's `Authorization` header or session cookie. `RealmMiddleware` never sees the upgrade, so the realm is resolved from it once per connection |
1169
+ | `TenantGuard`, `PermissionGuard` | Resolve the tenant and check permissions from the upgrade request |
1170
+ | `CsrfGuard` | Browsers cannot send the CSRF header on a WebSocket, so `csrf.webSocket` decides: `'reject'` (default) answers 403, `'skip'` allows. A connection with an `Authorization` header is allowed either way |
1171
+
1172
+ **Use `'skip'` only with an `Origin` check when the socket connects.** That check is what stops another site from opening a socket with your users' cookies.
1173
+
1174
+ With your own `graphql-ws` server, also pass the connection through as the context. Without it, guards receive no request and refuse every subscription with 401:
1175
+
1176
+ ```typescript
1177
+ useServer(
1178
+ {
1179
+ schema,
1180
+ context: (ctx) => ctx,
1181
+ onConnect: (ctx) => ALLOWED_ORIGINS.includes(ctx.extra.request.headers.origin ?? ''),
1182
+ },
1183
+ wsServer,
1184
+ );
1185
+ ```
1186
+
1187
+ With `GraphQLModule`'s `subscriptions: { 'graphql-ws': { onConnect } }`, the guards find the upgrade request on their own; put the same `onConnect` there.
1188
+
1189
+ `isWebSocketContext(context)` and `readCookie(request, name)` are exported for your own guards and connection handlers.
1190
+
1060
1191
  ## Utilities
1061
1192
 
1062
1193
  Helper functions exported for use in custom guards, middleware and loggers:
1063
1194
 
1064
1195
  | Function | Description |
1065
1196
  |----------|-------------|
1066
- | `getRequestFromContext(context)` | Extract request from `ExecutionContext` (handles GraphQL + HTTP) |
1197
+ | `getRequestFromContext(context)` | The request behind an `ExecutionContext`: HTTP, GraphQL, or a `graphql-ws` subscription's upgrade request. `undefined` when there is none |
1198
+ | `requireRequestFromContext(context)` | The same, but throws `UnauthorizedException` when there is no request |
1199
+ | `isWebSocketContext(context)` | Whether the context is a GraphQL subscription over a WebSocket |
1200
+ | `readCookie(request, name)` | A cookie's value from `request.cookies`, or parsed from the `Cookie` header (a WebSocket upgrade request has only the header) |
1067
1201
  | `extractIpAddress(request)` | Extract client IP (checks `clientIp`, `req.ip`, falls back to `'unknown'`) |
1068
1202
  | `isUserActiveByDefault(user)` | The default account-active predicate (see [Account Status](#account-status)) |
1069
1203
  | `emailForLog(email)`, `ipForLog(ip)` | An email or IP as it may appear in a log line — `emailHash=…` / `ipHash=…`, salted like the package's own logs |
@@ -1072,12 +1206,12 @@ Helper functions exported for use in custom guards, middleware and loggers:
1072
1206
  | `hashIp(ip, salt)` | HMAC-SHA256 IP hash (16 hex characters) used for rate-limit keys |
1073
1207
 
1074
1208
  ```typescript
1075
- import { getRequestFromContext, extractIpAddress } from '@ambushsoftworks/nestjs-auth-graphql';
1209
+ import { requireRequestFromContext, extractIpAddress } from '@ambushsoftworks/nestjs-auth-graphql';
1076
1210
 
1077
1211
  @Injectable()
1078
1212
  export class CustomGuard implements CanActivate {
1079
1213
  canActivate(context: ExecutionContext): boolean {
1080
- const request = getRequestFromContext(context);
1214
+ const request = requireRequestFromContext(context);
1081
1215
  const ip = extractIpAddress(request);
1082
1216
  // your logic
1083
1217
  return true;
@@ -1087,7 +1221,7 @@ export class CustomGuard implements CanActivate {
1087
1221
 
1088
1222
  ## Security Features
1089
1223
 
1090
- - **Refresh token rotation** with HMAC-SHA256 hashing and idempotent 10-second grace period
1224
+ - **Refresh token rotation** with HMAC-SHA256 hashing; a retried refresh gets the same pair for 10 seconds (configurable, shareable across instances, encrypted at rest)
1091
1225
  - **Bcrypt password hashing** with configurable rounds (default: 12)
1092
1226
  - **Account status enforcement** -- suspended and deleted users are rejected at login, on refresh and on every authenticated request (`ACCOUNT_INACTIVE`)
1093
1227
  - **AES-256-GCM encryption** for OAuth tokens at rest
@@ -1096,9 +1230,31 @@ export class CustomGuard implements CanActivate {
1096
1230
  - **Stateless CSRF protection** for OAuth flows via `OAuthStateService`
1097
1231
  - **`__Host-` cookie prefix** support for enhanced cookie security
1098
1232
  - **Separate HMAC secrets** for refresh tokens, verification codes, and OAuth state
1099
- - **Realm-based identity isolation** with JWT realm claim validation and realm-scoped rate limiting
1233
+ - **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
1100
1234
  - **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.
1101
1235
 
1236
+ ## Migrating to v0.11.0
1237
+
1238
+ **`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`.
1239
+
1240
+ **Subscriptions through `CsrfGuard`.** With cookie auth they answer 403 unless you set `csrf.webSocket: 'skip'`, together with an `Origin` check when the socket connects. They failed before 0.11.0 as well: with that same 403 on `GraphQLModule` subscriptions, or a `TypeError` on your own `graphql-ws` server. See [GraphQL Subscriptions](#graphql-subscriptions).
1241
+
1242
+ **Cookie auth no longer needs cookie-parser.** The access and refresh token cookies are read from the `Cookie` header when `request.cookies` is absent.
1243
+
1244
+ **More than one instance.** Set `refreshRetryCacheInstance` and `encryptionKey`, or retried refreshes that reach another instance sign users out; see [Refresh Retries](#refresh-retries). Boot now warns for each in-memory default in use. `RefreshTokenService`'s retry cache methods became async, which only matters if you call or override them.
1245
+
1246
+ ## Migrating to v0.10.0
1247
+
1248
+ No code change is required. Check the items that apply to you.
1249
+
1250
+ **Clients of the OAuth REST routes.** Four failures that answered 500 now answer 404, 403 or 429 with a `code`; see the table under [OAuth](#oauth). A client that shows a generic error for any failure keeps working. One that branched on 500, or on the old message `Account is locked. Please try again in N minutes.`, should read `code` instead. The lockout message is now the one `login` uses.
1251
+
1252
+ **API key guards.** `createAuthGuard(['api-key', 'jwt'])` now accepts JWTs. With `['api-key']` alone, an unknown key still gets 401, now with the guard's generic `Unauthorized` message rather than `Invalid API key`.
1253
+
1254
+ **Realms.** With realms enabled, a `BaseAuthResolver` flow or OAuth route reached by a request without a realm answers `400 Realm required`. Before `realm.skip`, `RealmMiddleware` made that impossible, so in practice this affects only code calling `perform*` methods without the GraphQL context, which now counts as having no realm. The OAuth routes also pass the realm to lockout checks, IP rate limiting and the failed-attempt reset. Their IP rate-limit counters move to the realm-prefixed keys `login` already uses (`auth:ipRate:<realm>:<ipHash>`), so existing counts for those routes start again.
1255
+
1256
+ **NestJS 11.** The package needs no change to run on it; CI now tests both majors.
1257
+
1102
1258
  ## Migrating to v0.9.0
1103
1259
 
1104
1260
  **Behaviour change — suspended and deleted accounts are rejected.** Before
@@ -18,6 +18,7 @@ import { IJwtPayloadFactory } from './interfaces/jwt-payload-factory.interface';
18
18
  import { IApiKeyRepository } from './interfaces/api-key-repository.interface';
19
19
  import { PasswordPolicyConfig } from './interfaces/password-policy-config.interface';
20
20
  import { IRateLimiter } from './interfaces/rate-limiter.interface';
21
+ import { IRefreshRetryCache } from './interfaces/refresh-retry-cache.interface';
21
22
  import { IEmailSender } from './interfaces/email-sender.interface';
22
23
  import { IEmailTemplateRenderer } from './interfaces/email-template-renderer.interface';
23
24
  import { EmailBrandingConfig } from './interfaces/email-branding-config.interface';
@@ -49,6 +50,9 @@ export interface AuthModuleOptions {
49
50
  tenantRepositoryInstance?: ITenantRepository;
50
51
  tenantExtractorInstance?: ITenantExtractor;
51
52
  realmExtractorInstance?: IRealmExtractor;
53
+ realm?: {
54
+ skip?: (path: string, request: Record<string, any>) => boolean;
55
+ };
52
56
  resourcePermissionRepositoryInstance?: IResourcePermissionRepository;
53
57
  jwtPayloadFactoryInstance?: IJwtPayloadFactory;
54
58
  apiKeyRepositoryInstance?: IApiKeyRepository;
@@ -76,6 +80,7 @@ export interface AuthModuleOptions {
76
80
  headerName?: string;
77
81
  requireInProduction?: boolean;
78
82
  exemptOperations?: string[];
83
+ webSocket?: 'reject' | 'skip';
79
84
  };
80
85
  jwtSecret: string;
81
86
  jwtExpiresIn?: string;
@@ -95,6 +100,8 @@ export interface AuthModuleOptions {
95
100
  encryptionKey?: string;
96
101
  passwordPolicy?: PasswordPolicyConfig;
97
102
  rateLimiterInstance?: IRateLimiter;
103
+ refreshGracePeriodSeconds?: number;
104
+ refreshRetryCacheInstance?: IRefreshRetryCache;
98
105
  bruteForce?: {
99
106
  ipRateLimit?: {
100
107
  maxAttempts: number;
@@ -119,9 +126,12 @@ export interface AuthModuleOptions {
119
126
  export interface AuthModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
120
127
  useFactory: (...args: any[]) => Promise<AuthModuleOptions> | AuthModuleOptions;
121
128
  inject?: any[];
129
+ oauthController?: boolean;
122
130
  }
123
131
  export declare function validateAuthModuleOptions(opts: AuthModuleOptions): void;
124
132
  export declare function describeIgnoredFeatureFlags(opts: AuthModuleOptions): string[];
133
+ export declare function describeIgnoredOptions(opts: AuthModuleOptions): string[];
134
+ export declare function describeInMemoryDefaults(opts: AuthModuleOptions): string[];
125
135
  export { AUTH_MODULE_OPTIONS, USER_REPOSITORY, REFRESH_TOKEN_REPOSITORY, EMAIL_SERVICE, SMS_SERVICE, AUTH_LIFECYCLE_HOOKS, VERIFICATION_REPOSITORY, BRUTE_FORCE_REPOSITORY, BIOMETRIC_REPOSITORY, AUTH_LOGGER, RATE_LIMITER, TENANT_REPOSITORY, TENANT_EXTRACTOR, RESOURCE_PERMISSION_REPOSITORY, JWT_PAYLOAD_FACTORY, API_KEY_REPOSITORY, } from './constants';
126
136
  export declare class AuthModule implements NestModule {
127
137
  configure(consumer: MiddlewareConsumer): void;
@@ -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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"}