@nestjs/authentication 0.0.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 (215) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +50 -0
  3. package/dist/account/email-verification.handler.d.ts +23 -0
  4. package/dist/account/email-verification.handler.js +17 -0
  5. package/dist/account/email-verification.service.d.ts +46 -0
  6. package/dist/account/email-verification.service.js +111 -0
  7. package/dist/account/email.util.d.ts +14 -0
  8. package/dist/account/email.util.js +28 -0
  9. package/dist/account/in-memory-email-token.store.d.ts +12 -0
  10. package/dist/account/in-memory-email-token.store.js +60 -0
  11. package/dist/account/password-reset.handler.d.ts +19 -0
  12. package/dist/account/password-reset.handler.js +9 -0
  13. package/dist/account/password-reset.service.d.ts +69 -0
  14. package/dist/account/password-reset.service.js +204 -0
  15. package/dist/authentication.constants.d.ts +13 -0
  16. package/dist/authentication.constants.js +13 -0
  17. package/dist/authentication.module-definition.d.ts +21 -0
  18. package/dist/authentication.module-definition.js +147 -0
  19. package/dist/authentication.module.d.ts +34 -0
  20. package/dist/authentication.module.js +139 -0
  21. package/dist/context/authentication-scope.service.d.ts +39 -0
  22. package/dist/context/authentication-scope.service.js +64 -0
  23. package/dist/context/authentication.context.d.ts +28 -0
  24. package/dist/context/authentication.context.js +58 -0
  25. package/dist/context/index.d.ts +2 -0
  26. package/dist/context/index.js +2 -0
  27. package/dist/decorators/authenticate.decorator.d.ts +10 -0
  28. package/dist/decorators/authenticate.decorator.js +18 -0
  29. package/dist/decorators/current-session.decorator.d.ts +2 -0
  30. package/dist/decorators/current-session.decorator.js +6 -0
  31. package/dist/decorators/current-user.decorator.d.ts +6 -0
  32. package/dist/decorators/current-user.decorator.js +11 -0
  33. package/dist/decorators/index.d.ts +4 -0
  34. package/dist/decorators/index.js +4 -0
  35. package/dist/decorators/public.decorator.d.ts +5 -0
  36. package/dist/decorators/public.decorator.js +6 -0
  37. package/dist/errors/authentication.error.d.ts +27 -0
  38. package/dist/errors/authentication.error.js +33 -0
  39. package/dist/errors/index.d.ts +7 -0
  40. package/dist/errors/index.js +7 -0
  41. package/dist/errors/jwt.error.d.ts +9 -0
  42. package/dist/errors/jwt.error.js +12 -0
  43. package/dist/errors/magic-link.error.d.ts +18 -0
  44. package/dist/errors/magic-link.error.js +21 -0
  45. package/dist/errors/mfa-already-enrolled.error.d.ts +14 -0
  46. package/dist/errors/mfa-already-enrolled.error.js +17 -0
  47. package/dist/errors/oidc.error.d.ts +15 -0
  48. package/dist/errors/oidc.error.js +13 -0
  49. package/dist/errors/refresh-token.error.d.ts +10 -0
  50. package/dist/errors/refresh-token.error.js +12 -0
  51. package/dist/errors/secret-decryption.error.d.ts +3 -0
  52. package/dist/errors/secret-decryption.error.js +6 -0
  53. package/dist/events/authentication-events.interface.d.ts +121 -0
  54. package/dist/events/authentication-events.interface.js +1 -0
  55. package/dist/events/authentication-events.service.d.ts +19 -0
  56. package/dist/events/authentication-events.service.js +39 -0
  57. package/dist/events/authentication.channels.d.ts +4 -0
  58. package/dist/events/authentication.channels.js +11 -0
  59. package/dist/events/index.d.ts +3 -0
  60. package/dist/events/index.js +3 -0
  61. package/dist/guards/authentication.guard.d.ts +57 -0
  62. package/dist/guards/authentication.guard.js +171 -0
  63. package/dist/guards/index.d.ts +1 -0
  64. package/dist/guards/index.js +1 -0
  65. package/dist/index.d.ts +52 -0
  66. package/dist/index.js +52 -0
  67. package/dist/interceptors/authentication-scope.interceptor.d.ts +20 -0
  68. package/dist/interceptors/authentication-scope.interceptor.js +48 -0
  69. package/dist/interceptors/index.d.ts +1 -0
  70. package/dist/interceptors/index.js +1 -0
  71. package/dist/interfaces/api-key.interface.d.ts +41 -0
  72. package/dist/interfaces/api-key.interface.js +1 -0
  73. package/dist/interfaces/authenticate-options.interface.d.ts +31 -0
  74. package/dist/interfaces/authenticate-options.interface.js +1 -0
  75. package/dist/interfaces/authentication-error-options.interface.d.ts +8 -0
  76. package/dist/interfaces/authentication-error-options.interface.js +1 -0
  77. package/dist/interfaces/authentication-module-options.interface.d.ts +58 -0
  78. package/dist/interfaces/authentication-module-options.interface.js +1 -0
  79. package/dist/interfaces/authentication-registry.interface.d.ts +41 -0
  80. package/dist/interfaces/authentication-registry.interface.js +1 -0
  81. package/dist/interfaces/authentication-result.interface.d.ts +25 -0
  82. package/dist/interfaces/authentication-result.interface.js +1 -0
  83. package/dist/interfaces/authentication-storage.interface.d.ts +29 -0
  84. package/dist/interfaces/authentication-storage.interface.js +1 -0
  85. package/dist/interfaces/duration.interface.d.ts +2 -0
  86. package/dist/interfaces/duration.interface.js +1 -0
  87. package/dist/interfaces/email-token-store.interface.d.ts +52 -0
  88. package/dist/interfaces/email-token-store.interface.js +1 -0
  89. package/dist/interfaces/email-verification.interface.d.ts +18 -0
  90. package/dist/interfaces/email-verification.interface.js +1 -0
  91. package/dist/interfaces/index.d.ts +27 -0
  92. package/dist/interfaces/index.js +27 -0
  93. package/dist/interfaces/jwt-options.interface.d.ts +68 -0
  94. package/dist/interfaces/jwt-options.interface.js +1 -0
  95. package/dist/interfaces/jwt.interface.d.ts +36 -0
  96. package/dist/interfaces/jwt.interface.js +1 -0
  97. package/dist/interfaces/magic-link-store.interface.d.ts +36 -0
  98. package/dist/interfaces/magic-link-store.interface.js +1 -0
  99. package/dist/interfaces/magic-link.interface.d.ts +55 -0
  100. package/dist/interfaces/magic-link.interface.js +1 -0
  101. package/dist/interfaces/mfa-options.interface.d.ts +44 -0
  102. package/dist/interfaces/mfa-options.interface.js +1 -0
  103. package/dist/interfaces/mfa-store.interface.d.ts +70 -0
  104. package/dist/interfaces/mfa-store.interface.js +1 -0
  105. package/dist/interfaces/oidc-provider.interface.d.ts +56 -0
  106. package/dist/interfaces/oidc-provider.interface.js +1 -0
  107. package/dist/interfaces/oidc-state-store.interface.d.ts +25 -0
  108. package/dist/interfaces/oidc-state-store.interface.js +1 -0
  109. package/dist/interfaces/oidc.interface.d.ts +84 -0
  110. package/dist/interfaces/oidc.interface.js +1 -0
  111. package/dist/interfaces/password-hasher-options.interface.d.ts +17 -0
  112. package/dist/interfaces/password-hasher-options.interface.js +1 -0
  113. package/dist/interfaces/password-reset.interface.d.ts +49 -0
  114. package/dist/interfaces/password-reset.interface.js +1 -0
  115. package/dist/interfaces/refresh-token-options.interface.d.ts +10 -0
  116. package/dist/interfaces/refresh-token-options.interface.js +1 -0
  117. package/dist/interfaces/refresh-token-store.interface.d.ts +61 -0
  118. package/dist/interfaces/refresh-token-store.interface.js +1 -0
  119. package/dist/interfaces/session-store.interface.d.ts +53 -0
  120. package/dist/interfaces/session-store.interface.js +1 -0
  121. package/dist/interfaces/session.interface.d.ts +50 -0
  122. package/dist/interfaces/session.interface.js +1 -0
  123. package/dist/interfaces/sign-in-options.interface.d.ts +9 -0
  124. package/dist/interfaces/sign-in-options.interface.js +1 -0
  125. package/dist/interfaces/token.interface.d.ts +30 -0
  126. package/dist/interfaces/token.interface.js +1 -0
  127. package/dist/jwt/amr.util.d.ts +9 -0
  128. package/dist/jwt/amr.util.js +11 -0
  129. package/dist/jwt/in-memory-refresh-token.store.d.ts +29 -0
  130. package/dist/jwt/in-memory-refresh-token.store.js +67 -0
  131. package/dist/jwt/jwks.client.d.ts +34 -0
  132. package/dist/jwt/jwks.client.js +154 -0
  133. package/dist/jwt/jws.util.d.ts +45 -0
  134. package/dist/jwt/jws.util.js +282 -0
  135. package/dist/jwt/jwt-bearer.provider.d.ts +48 -0
  136. package/dist/jwt/jwt-bearer.provider.js +126 -0
  137. package/dist/jwt/jwt-signer.service.d.ts +19 -0
  138. package/dist/jwt/jwt-signer.service.js +36 -0
  139. package/dist/jwt/jwt-verifier.service.d.ts +22 -0
  140. package/dist/jwt/jwt-verifier.service.js +109 -0
  141. package/dist/jwt/token.service.d.ts +81 -0
  142. package/dist/jwt/token.service.js +230 -0
  143. package/dist/magic-link/in-memory-magic-link.store.d.ts +12 -0
  144. package/dist/magic-link/in-memory-magic-link.store.js +45 -0
  145. package/dist/magic-link/magic-link.handler.d.ts +25 -0
  146. package/dist/magic-link/magic-link.handler.js +14 -0
  147. package/dist/magic-link/magic-link.service.d.ts +79 -0
  148. package/dist/magic-link/magic-link.service.js +215 -0
  149. package/dist/mfa/in-memory-mfa.store.d.ts +25 -0
  150. package/dist/mfa/in-memory-mfa.store.js +73 -0
  151. package/dist/mfa/mfa.service.d.ts +104 -0
  152. package/dist/mfa/mfa.service.js +346 -0
  153. package/dist/mfa/otp.util.d.ts +7 -0
  154. package/dist/mfa/otp.util.js +52 -0
  155. package/dist/mfa/secret-cipher.service.d.ts +28 -0
  156. package/dist/mfa/secret-cipher.service.js +106 -0
  157. package/dist/oidc/in-memory-oidc-state.store.d.ts +13 -0
  158. package/dist/oidc/in-memory-oidc-state.store.js +45 -0
  159. package/dist/oidc/oidc-account.resolver.d.ts +23 -0
  160. package/dist/oidc/oidc-account.resolver.js +16 -0
  161. package/dist/oidc/oidc.client.d.ts +44 -0
  162. package/dist/oidc/oidc.client.js +286 -0
  163. package/dist/oidc/oidc.presets.d.ts +24 -0
  164. package/dist/oidc/oidc.presets.js +53 -0
  165. package/dist/oidc/oidc.service.d.ts +88 -0
  166. package/dist/oidc/oidc.service.js +259 -0
  167. package/dist/providers/api-key.provider.d.ts +51 -0
  168. package/dist/providers/api-key.provider.js +93 -0
  169. package/dist/providers/authentication.provider.d.ts +40 -0
  170. package/dist/providers/authentication.provider.js +33 -0
  171. package/dist/providers/index.d.ts +2 -0
  172. package/dist/providers/index.js +2 -0
  173. package/dist/services/authentication-registry.service.d.ts +75 -0
  174. package/dist/services/authentication-registry.service.js +235 -0
  175. package/dist/services/index.d.ts +3 -0
  176. package/dist/services/index.js +3 -0
  177. package/dist/services/password-hasher.service.d.ts +47 -0
  178. package/dist/services/password-hasher.service.js +170 -0
  179. package/dist/services/ws-authenticator.service.d.ts +38 -0
  180. package/dist/services/ws-authenticator.service.js +92 -0
  181. package/dist/session/cookies.util.d.ts +34 -0
  182. package/dist/session/cookies.util.js +82 -0
  183. package/dist/session/in-memory-session.store.d.ts +33 -0
  184. package/dist/session/in-memory-session.store.js +60 -0
  185. package/dist/session/session-cookie.provider.d.ts +36 -0
  186. package/dist/session/session-cookie.provider.js +58 -0
  187. package/dist/session/session.service.d.ts +97 -0
  188. package/dist/session/session.service.js +208 -0
  189. package/dist/session/sign-in.service.d.ts +87 -0
  190. package/dist/session/sign-in.service.js +206 -0
  191. package/dist/storage/authentication.storage.d.ts +130 -0
  192. package/dist/storage/authentication.storage.js +350 -0
  193. package/dist/storage/index.d.ts +1 -0
  194. package/dist/storage/index.js +1 -0
  195. package/dist/testing/index.d.ts +39 -0
  196. package/dist/testing/index.js +531 -0
  197. package/dist/utils/api-key.util.d.ts +10 -0
  198. package/dist/utils/api-key.util.js +10 -0
  199. package/dist/utils/auth-state.util.d.ts +54 -0
  200. package/dist/utils/auth-state.util.js +209 -0
  201. package/dist/utils/bearer.util.d.ts +9 -0
  202. package/dist/utils/bearer.util.js +21 -0
  203. package/dist/utils/cross-origin.util.d.ts +29 -0
  204. package/dist/utils/cross-origin.util.js +90 -0
  205. package/dist/utils/crypto.util.d.ts +19 -0
  206. package/dist/utils/crypto.util.js +38 -0
  207. package/dist/utils/duration.util.d.ts +9 -0
  208. package/dist/utils/duration.util.js +44 -0
  209. package/dist/utils/index.d.ts +8 -0
  210. package/dist/utils/index.js +8 -0
  211. package/dist/utils/options.util.d.ts +20 -0
  212. package/dist/utils/options.util.js +44 -0
  213. package/dist/utils/transport-errors.util.d.ts +33 -0
  214. package/dist/utils/transport-errors.util.js +70 -0
  215. package/package.json +108 -0
@@ -0,0 +1,64 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { AsyncLocalStorage } from 'node:async_hooks';
8
+ import { Injectable } from '@nestjs/common';
9
+ /**
10
+ * The call the interceptor is handling, for the param decorators, which have no instance to ask:
11
+ * one store for the process, entered with the instance's own by `AuthenticationScopeInterceptor`.
12
+ */
13
+ const calls = new AsyncLocalStorage();
14
+ /** @internal Runs `fn` as the handling of this call (the interceptor, around `next.handle()`). */
15
+ export function runCall(scope, fn) {
16
+ return calls.run(scope, fn);
17
+ }
18
+ /**
19
+ * @internal What the handler of this call sees: the result the guard recorded for it, when the
20
+ * interceptor is handling this handler (param decorators are resolved inside it).
21
+ */
22
+ export function scopedResult(context) {
23
+ const call = calls.getStore();
24
+ return call?.context && call.context.getHandler() === context.getHandler() ? call.result : undefined;
25
+ }
26
+ /**
27
+ * @internal The per-call scope behind `AuthenticationContext` and
28
+ * `SignInService`: its own `AsyncLocalStorage`, opened around each handler
29
+ * by `AuthenticationScopeInterceptor`.
30
+ */
31
+ let AuthenticationScope = class AuthenticationScope {
32
+ constructor() {
33
+ this.storage = new AsyncLocalStorage();
34
+ }
35
+ get current() {
36
+ return this.storage.getStore();
37
+ }
38
+ run(scope, fn) {
39
+ return this.storage.run(scope, fn);
40
+ }
41
+ /**
42
+ * The HTTP request and response of the current call: an HTTP handler, or
43
+ * a GraphQL resolver whose context carries `req` (and `res`).
44
+ */
45
+ exchange() {
46
+ const context = this.current?.context;
47
+ switch (context?.getType()) {
48
+ case 'http': {
49
+ const http = context.switchToHttp();
50
+ return { request: http.getRequest(), response: http.getResponse() };
51
+ }
52
+ case 'graphql': {
53
+ const gql = context.getArgByIndex(2);
54
+ return gql?.req ? { request: gql.req, response: gql.res } : undefined;
55
+ }
56
+ default:
57
+ return undefined;
58
+ }
59
+ }
60
+ };
61
+ AuthenticationScope = __decorate([
62
+ Injectable()
63
+ ], AuthenticationScope);
64
+ export { AuthenticationScope };
@@ -0,0 +1,28 @@
1
+ import type { AuthenticatedSession, AuthenticatedUser, AuthenticationResult } from '../interfaces/authentication-result.interface.js';
2
+ import { AuthenticationScope } from './authentication-scope.service.js';
3
+ /**
4
+ * The current user and session, readable from any singleton provider
5
+ * without passing the request down. Correct in the handler and in
6
+ * everything it calls or awaits, however many requests run at once. Empty
7
+ * in middleware, guards and exception filters, in interceptors that run
8
+ * before the module's own (an app's `APP_INTERCEPTOR` declared ahead of it:
9
+ * read `@CurrentUser()` or `request.user` there), and outside requests.
10
+ * A stream a handler returns but did not create (a shared `Subject`) runs
11
+ * its operators in the scope of whoever emits: read the user before
12
+ * building it.
13
+ */
14
+ export declare class AuthenticationContext<TUser = AuthenticatedUser, TSession = AuthenticatedSession> {
15
+ private readonly scope;
16
+ constructor(scope?: AuthenticationScope);
17
+ /** The user, or `null` when anonymous or outside a request. */
18
+ get user(): TUser | null;
19
+ get session(): TSession | null;
20
+ get isAuthenticated(): boolean;
21
+ /**
22
+ * The user, or an {@link AuthenticationError}: a 401 on any transport when
23
+ * thrown under a handler, a plain error in a queue worker.
24
+ */
25
+ requireUser(): TUser;
26
+ /** Runs `fn` as `result.user`, for queue workers, cron jobs and tests. */
27
+ run<R>(result: AuthenticationResult<TUser, TSession> | null, fn: () => R): R;
28
+ }
@@ -0,0 +1,58 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Injectable } from '@nestjs/common';
11
+ import { AuthenticationError } from '../errors/authentication.error.js';
12
+ import { AuthenticationScope } from './authentication-scope.service.js';
13
+ /**
14
+ * The current user and session, readable from any singleton provider
15
+ * without passing the request down. Correct in the handler and in
16
+ * everything it calls or awaits, however many requests run at once. Empty
17
+ * in middleware, guards and exception filters, in interceptors that run
18
+ * before the module's own (an app's `APP_INTERCEPTOR` declared ahead of it:
19
+ * read `@CurrentUser()` or `request.user` there), and outside requests.
20
+ * A stream a handler returns but did not create (a shared `Subject`) runs
21
+ * its operators in the scope of whoever emits: read the user before
22
+ * building it.
23
+ */
24
+ let AuthenticationContext = class AuthenticationContext {
25
+ constructor(scope = new AuthenticationScope()) {
26
+ this.scope = scope;
27
+ }
28
+ /** The user, or `null` when anonymous or outside a request. */
29
+ get user() {
30
+ return this.scope.current?.result?.user ?? null;
31
+ }
32
+ get session() {
33
+ return this.scope.current?.result?.session ?? null;
34
+ }
35
+ get isAuthenticated() {
36
+ return !!this.scope.current?.result?.user;
37
+ }
38
+ /**
39
+ * The user, or an {@link AuthenticationError}: a 401 on any transport when
40
+ * thrown under a handler, a plain error in a queue worker.
41
+ */
42
+ requireUser() {
43
+ const user = this.user;
44
+ if (!user) {
45
+ throw new AuthenticationError();
46
+ }
47
+ return user;
48
+ }
49
+ /** Runs `fn` as `result.user`, for queue workers, cron jobs and tests. */
50
+ run(result, fn) {
51
+ return this.scope.run({ result }, fn);
52
+ }
53
+ };
54
+ AuthenticationContext = __decorate([
55
+ Injectable(),
56
+ __metadata("design:paramtypes", [AuthenticationScope])
57
+ ], AuthenticationContext);
58
+ export { AuthenticationContext };
@@ -0,0 +1,2 @@
1
+ export * from './authentication-scope.service.js';
2
+ export * from './authentication.context.js';
@@ -0,0 +1,2 @@
1
+ export * from './authentication-scope.service.js';
2
+ export * from './authentication.context.js';
@@ -0,0 +1,10 @@
1
+ import type { AuthenticateOptions, RouteAuthentication } from '../interfaces/authenticate-options.interface.js';
2
+ /** Merges into the metadata already on the class or method, so decorators can be stacked. */
3
+ export declare function route(value: RouteAuthentication): ClassDecorator & MethodDecorator;
4
+ /**
5
+ * Configures authentication for a controller or a handler. Every route
6
+ * already requires a signed-in user; use this to relax that (`optional`),
7
+ * tighten it (`mfa`, `verifiedEmail`, `providers`), or require it again under a `@Public()`
8
+ * class. Method options merge over class options, field by field.
9
+ */
10
+ export declare const Authenticate: (options?: AuthenticateOptions) => ClassDecorator & MethodDecorator;
@@ -0,0 +1,18 @@
1
+ import { AUTHENTICATION_METADATA } from '../authentication.constants.js';
2
+ /** Merges into the metadata already on the class or method, so decorators can be stacked. */
3
+ export function route(value) {
4
+ const defined = Object.fromEntries(Object.entries(value).filter(([, field]) => field !== undefined));
5
+ const decorator = (target, _key, descriptor) => {
6
+ const holder = descriptor ? descriptor.value : target;
7
+ const existing = Reflect.getMetadata(AUTHENTICATION_METADATA, holder);
8
+ Reflect.defineMetadata(AUTHENTICATION_METADATA, { ...existing, ...defined }, holder);
9
+ };
10
+ return decorator;
11
+ }
12
+ /**
13
+ * Configures authentication for a controller or a handler. Every route
14
+ * already requires a signed-in user; use this to relax that (`optional`),
15
+ * tighten it (`mfa`, `verifiedEmail`, `providers`), or require it again under a `@Public()`
16
+ * class. Method options merge over class options, field by field.
17
+ */
18
+ export const Authenticate = (options = {}) => route({ ...options, public: false });
@@ -0,0 +1,2 @@
1
+ /** The provider's session object (a `SessionRecord`, JWT claims, an `ApiKeySession`), or `null`. */
2
+ export declare const CurrentSession: (...dataOrPipes: unknown[]) => ParameterDecorator;
@@ -0,0 +1,6 @@
1
+ import { createParamDecorator } from '@nestjs/common';
2
+ import { resultOf } from '../utils/auth-state.util.js';
3
+ /** The provider's session object (a `SessionRecord`, JWT claims, an `ApiKeySession`), or `null`. */
4
+ export const CurrentSession = createParamDecorator((_, context) => {
5
+ return resultOf(context)?.session ?? null;
6
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The authenticated user, or `null` on `@Public()` and anonymous optional
3
+ * calls. `@CurrentUser('email')` picks one property; the key is checked
4
+ * against the `AuthenticationTypes` augmentation.
5
+ */
6
+ export declare const CurrentUser: (...dataOrPipes: (string | import("@nestjs/common").ParameterDecoratorOptions | import("@nestjs/common").PipeTransform<any, any> | import("@nestjs/common").Type<import("@nestjs/common").PipeTransform<any, any>> | undefined)[]) => ParameterDecorator;
@@ -0,0 +1,11 @@
1
+ import { createParamDecorator } from '@nestjs/common';
2
+ import { resultOf } from '../utils/auth-state.util.js';
3
+ /**
4
+ * The authenticated user, or `null` on `@Public()` and anonymous optional
5
+ * calls. `@CurrentUser('email')` picks one property; the key is checked
6
+ * against the `AuthenticationTypes` augmentation.
7
+ */
8
+ export const CurrentUser = createParamDecorator((key, context) => {
9
+ const user = resultOf(context)?.user ?? null;
10
+ return key && user ? user[key] : user;
11
+ });
@@ -0,0 +1,4 @@
1
+ export * from './authenticate.decorator.js';
2
+ export * from './current-session.decorator.js';
3
+ export * from './current-user.decorator.js';
4
+ export * from './public.decorator.js';
@@ -0,0 +1,4 @@
1
+ export * from './authenticate.decorator.js';
2
+ export * from './current-session.decorator.js';
3
+ export * from './current-user.decorator.js';
4
+ export * from './public.decorator.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Skips authentication: no provider runs, and `@CurrentUser()` is `null`.
3
+ * For health checks, the public catalog, and the routes that sign users in.
4
+ */
5
+ export declare const Public: () => ClassDecorator & MethodDecorator;
@@ -0,0 +1,6 @@
1
+ import { route } from './authenticate.decorator.js';
2
+ /**
3
+ * Skips authentication: no provider runs, and `@CurrentUser()` is `null`.
4
+ * For health checks, the public catalog, and the routes that sign users in.
5
+ */
6
+ export const Public = () => route({ public: true });
@@ -0,0 +1,27 @@
1
+ import type { AuthenticationErrorOptions } from '../interfaces/authentication-error-options.interface.js';
2
+ /**
3
+ * The base class of this package's errors, and on its own the error for
4
+ * credentials that are missing or failed verification: a 401 on every
5
+ * transport.
6
+ *
7
+ * - Thrown by a provider, the guard answers with it and sends `challenge`
8
+ * as the `WWW-Authenticate` header.
9
+ * - Thrown by a handler or anything it calls (`requireUser()`, a failed
10
+ * `TokenService.refresh()`), the module's interceptor turns it into the
11
+ * transport's error for its `status`: an HTTP 401 (409 for
12
+ * `MfaAlreadyEnrolledError`), GraphQL `UNAUTHENTICATED`, a `WsException`
13
+ * or an `RpcException`.
14
+ * - Elsewhere (a queue worker), it is a plain `Error`.
15
+ */
16
+ export declare class AuthenticationError extends Error {
17
+ /**
18
+ * 401, or 409 for `MfaAlreadyEnrolledError`: the caller's fault, not an
19
+ * outage, so other packages classify it without importing this class
20
+ * (`@nestjs/resilience` neither retries it nor counts it against a
21
+ * circuit breaker).
22
+ */
23
+ readonly status: 401 | 403 | 409;
24
+ readonly challenge?: string;
25
+ readonly code?: string;
26
+ constructor(message?: string, { challenge, code, cause }?: AuthenticationErrorOptions);
27
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The base class of this package's errors, and on its own the error for
3
+ * credentials that are missing or failed verification: a 401 on every
4
+ * transport.
5
+ *
6
+ * - Thrown by a provider, the guard answers with it and sends `challenge`
7
+ * as the `WWW-Authenticate` header.
8
+ * - Thrown by a handler or anything it calls (`requireUser()`, a failed
9
+ * `TokenService.refresh()`), the module's interceptor turns it into the
10
+ * transport's error for its `status`: an HTTP 401 (409 for
11
+ * `MfaAlreadyEnrolledError`), GraphQL `UNAUTHENTICATED`, a `WsException`
12
+ * or an `RpcException`.
13
+ * - Elsewhere (a queue worker), it is a plain `Error`.
14
+ */
15
+ export class AuthenticationError extends Error {
16
+ constructor(message = 'Unauthorized', { challenge, code, cause } = {}) {
17
+ super(message, cause === undefined ? undefined : { cause });
18
+ /**
19
+ * 401, or 409 for `MfaAlreadyEnrolledError`: the caller's fault, not an
20
+ * outage, so other packages classify it without importing this class
21
+ * (`@nestjs/resilience` neither retries it nor counts it against a
22
+ * circuit breaker).
23
+ */
24
+ this.status = 401;
25
+ this.name = new.target.name;
26
+ if (challenge !== undefined) {
27
+ this.challenge = challenge;
28
+ }
29
+ if (code !== undefined) {
30
+ this.code = code;
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,7 @@
1
+ export * from './authentication.error.js';
2
+ export * from './jwt.error.js';
3
+ export * from './magic-link.error.js';
4
+ export * from './mfa-already-enrolled.error.js';
5
+ export * from './oidc.error.js';
6
+ export * from './refresh-token.error.js';
7
+ export * from './secret-decryption.error.js';
@@ -0,0 +1,7 @@
1
+ export * from './authentication.error.js';
2
+ export * from './jwt.error.js';
3
+ export * from './magic-link.error.js';
4
+ export * from './mfa-already-enrolled.error.js';
5
+ export * from './oidc.error.js';
6
+ export * from './refresh-token.error.js';
7
+ export * from './secret-decryption.error.js';
@@ -0,0 +1,9 @@
1
+ import { AuthenticationError } from './authentication.error.js';
2
+ /**
3
+ * A token failed verification: malformed, badly signed, expired, for
4
+ * another issuer or audience. An {@link AuthenticationError} (401), so a
5
+ * route that lets one escape answers 401 on any transport.
6
+ */
7
+ export declare class JwtError extends AuthenticationError {
8
+ constructor(message: string);
9
+ }
@@ -0,0 +1,12 @@
1
+ import { AuthenticationError } from './authentication.error.js';
2
+ /**
3
+ * A token failed verification: malformed, badly signed, expired, for
4
+ * another issuer or audience. An {@link AuthenticationError} (401), so a
5
+ * route that lets one escape answers 401 on any transport.
6
+ */
7
+ export class JwtError extends AuthenticationError {
8
+ constructor(message) {
9
+ super(message);
10
+ this.name = 'JwtError';
11
+ }
12
+ }
@@ -0,0 +1,18 @@
1
+ import { AuthenticationError } from './authentication.error.js';
2
+ /**
3
+ * A link was presented in a browser other than the one that requested it
4
+ * (see `magicLink.bindToBrowser`). The one refusal `consume()` tells
5
+ * apart: the customer can act on it (open the link where they asked for
6
+ * it, or request a new one here), and it is decided before the link is
7
+ * looked up, so it reveals nothing about the token. Unknown, used, expired
8
+ * and refused links share one answer, `null`.
9
+ *
10
+ * An `AuthenticationError`: a route that lets it escape answers 401 on any
11
+ * transport, with `not_this_browser` as the body's `error`, the way
12
+ * `TokenService.issue()` answers `mfa_required`.
13
+ */
14
+ export declare class MagicLinkError extends AuthenticationError {
15
+ /** Why the link was refused: the only reason apps are told. */
16
+ readonly reason: 'not-this-browser';
17
+ constructor();
18
+ }
@@ -0,0 +1,21 @@
1
+ import { AuthenticationError } from './authentication.error.js';
2
+ /**
3
+ * A link was presented in a browser other than the one that requested it
4
+ * (see `magicLink.bindToBrowser`). The one refusal `consume()` tells
5
+ * apart: the customer can act on it (open the link where they asked for
6
+ * it, or request a new one here), and it is decided before the link is
7
+ * looked up, so it reveals nothing about the token. Unknown, used, expired
8
+ * and refused links share one answer, `null`.
9
+ *
10
+ * An `AuthenticationError`: a route that lets it escape answers 401 on any
11
+ * transport, with `not_this_browser` as the body's `error`, the way
12
+ * `TokenService.issue()` answers `mfa_required`.
13
+ */
14
+ export class MagicLinkError extends AuthenticationError {
15
+ constructor() {
16
+ super('Open the link in the browser you requested it from, or request a new one here', { code: 'not_this_browser' });
17
+ /** Why the link was refused: the only reason apps are told. */
18
+ this.reason = 'not-this-browser';
19
+ this.name = 'MagicLinkError';
20
+ }
21
+ }
@@ -0,0 +1,14 @@
1
+ import { AuthenticationError } from './authentication.error.js';
2
+ /**
3
+ * Thrown by `MfaService.enroll()` when the user already has a confirmed
4
+ * authenticator and `replace` was not requested: overwriting it would turn
5
+ * the second factor off until the new one is confirmed. A route that lets
6
+ * it escape answers 409 on any transport. To replace an authenticator, call
7
+ * `enroll(…, { replace: true })` from a step-up route
8
+ * (`@Authenticate({ mfa: true })`), or `disable()` first.
9
+ */
10
+ export declare class MfaAlreadyEnrolledError extends AuthenticationError {
11
+ readonly userId: string;
12
+ readonly status = 409;
13
+ constructor(userId: string);
14
+ }
@@ -0,0 +1,17 @@
1
+ import { AuthenticationError } from './authentication.error.js';
2
+ /**
3
+ * Thrown by `MfaService.enroll()` when the user already has a confirmed
4
+ * authenticator and `replace` was not requested: overwriting it would turn
5
+ * the second factor off until the new one is confirmed. A route that lets
6
+ * it escape answers 409 on any transport. To replace an authenticator, call
7
+ * `enroll(…, { replace: true })` from a step-up route
8
+ * (`@Authenticate({ mfa: true })`), or `disable()` first.
9
+ */
10
+ export class MfaAlreadyEnrolledError extends AuthenticationError {
11
+ constructor(userId) {
12
+ super('Authenticator already enrolled');
13
+ this.userId = userId;
14
+ this.status = 409;
15
+ this.name = 'MfaAlreadyEnrolledError';
16
+ }
17
+ }
@@ -0,0 +1,15 @@
1
+ export declare class OidcError extends Error {
2
+ /**
3
+ * `request`: bad or forged callback (400). `verification`: the IdP's
4
+ * answer failed checks (401). `unavailable`: the IdP is down or
5
+ * misconfigured (502), which is no fault of the user's.
6
+ */
7
+ readonly kind: 'request' | 'verification' | 'unavailable';
8
+ constructor(message: string,
9
+ /**
10
+ * `request`: bad or forged callback (400). `verification`: the IdP's
11
+ * answer failed checks (401). `unavailable`: the IdP is down or
12
+ * misconfigured (502), which is no fault of the user's.
13
+ */
14
+ kind: 'request' | 'verification' | 'unavailable');
15
+ }
@@ -0,0 +1,13 @@
1
+ export class OidcError extends Error {
2
+ constructor(message,
3
+ /**
4
+ * `request`: bad or forged callback (400). `verification`: the IdP's
5
+ * answer failed checks (401). `unavailable`: the IdP is down or
6
+ * misconfigured (502), which is no fault of the user's.
7
+ */
8
+ kind) {
9
+ super(message);
10
+ this.kind = kind;
11
+ this.name = 'OidcError';
12
+ }
13
+ }
@@ -0,0 +1,10 @@
1
+ import type { RefreshTokenFailure } from '../interfaces/refresh-token-options.interface.js';
2
+ import { AuthenticationError } from './authentication.error.js';
3
+ /**
4
+ * A refresh token was refused. An {@link AuthenticationError}, so a route
5
+ * that lets it escape answers 401 on any transport.
6
+ */
7
+ export declare class RefreshTokenError extends AuthenticationError {
8
+ readonly reason: RefreshTokenFailure;
9
+ constructor(reason: RefreshTokenFailure);
10
+ }
@@ -0,0 +1,12 @@
1
+ import { AuthenticationError } from './authentication.error.js';
2
+ /**
3
+ * A refresh token was refused. An {@link AuthenticationError}, so a route
4
+ * that lets it escape answers 401 on any transport.
5
+ */
6
+ export class RefreshTokenError extends AuthenticationError {
7
+ constructor(reason) {
8
+ super(`Refresh token ${reason}`);
9
+ this.reason = reason;
10
+ this.name = 'RefreshTokenError';
11
+ }
12
+ }
@@ -0,0 +1,3 @@
1
+ export declare class SecretDecryptionError extends Error {
2
+ constructor(message: string);
3
+ }
@@ -0,0 +1,6 @@
1
+ export class SecretDecryptionError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = 'SecretDecryptionError';
5
+ }
6
+ }
@@ -0,0 +1,121 @@
1
+ import type { MfaState } from '../interfaces/authentication-result.interface.js';
2
+ /**
3
+ * A first factor signed a user in: a cookie session (`SignInService`), or a
4
+ * refresh-token family for a token client (`TokenService.issue()`).
5
+ */
6
+ export interface AuthenticationSignInEvent {
7
+ type: 'sign-in';
8
+ userId: string;
9
+ /** The new cookie session. */
10
+ sessionId?: string;
11
+ /** The new refresh-token family. */
12
+ tokenFamilyId?: string;
13
+ /** How the user proved who they are, when the caller said: `password`, `magic-link`, `oidc:google`. */
14
+ method?: string;
15
+ /**
16
+ * `pending` while the session still needs its second factor; `verified`
17
+ * for tokens issued with one (`TokenService.issue()`).
18
+ */
19
+ mfa?: MfaState;
20
+ /** What the session stores next to the user (`session.metadata`). */
21
+ metadata?: Record<string, unknown>;
22
+ }
23
+ /** A TOTP or recovery code was accepted, at sign-in or for a token client. */
24
+ export interface AuthenticationMfaVerifiedEvent {
25
+ type: 'mfa-verified';
26
+ userId: string;
27
+ method: 'totp' | 'recovery-code';
28
+ }
29
+ /** A code was refused. `locked` once the user reached `mfa.maxAttempts`. */
30
+ export interface AuthenticationMfaFailedEvent {
31
+ type: 'mfa-failed';
32
+ userId: string;
33
+ method: 'totp' | 'recovery-code';
34
+ /** Failures within `mfa.lockoutWindow`, this one included. */
35
+ failures: number;
36
+ locked: boolean;
37
+ }
38
+ /** An authenticator was confirmed: a first one, or a replacement (`replaced`). */
39
+ export interface AuthenticationMfaEnabledEvent {
40
+ type: 'mfa-enabled';
41
+ userId: string;
42
+ replaced: boolean;
43
+ }
44
+ /** The authenticator and the recovery codes were removed. */
45
+ export interface AuthenticationMfaDisabledEvent {
46
+ type: 'mfa-disabled';
47
+ userId: string;
48
+ }
49
+ /** A new batch of recovery codes replaced the previous one. */
50
+ export interface AuthenticationRecoveryCodesGeneratedEvent {
51
+ type: 'recovery-codes-generated';
52
+ userId: string;
53
+ count: number;
54
+ }
55
+ /**
56
+ * A spent refresh token came back, so two parties hold it: the family was
57
+ * revoked. A signal of token theft.
58
+ */
59
+ export interface AuthenticationRefreshTokenReusedEvent {
60
+ type: 'refresh-token-reused';
61
+ userId: string;
62
+ tokenFamilyId: string;
63
+ }
64
+ /**
65
+ * A session or a token client was signed out: one session
66
+ * (`SignInService.signOut()`, `SessionService.revoke()`), one refresh-token
67
+ * family (`TokenService.revoke()`), or all of them (`everywhere`,
68
+ * `SignInService.signOutEverywhere()`).
69
+ */
70
+ export interface AuthenticationSignOutEvent {
71
+ type: 'sign-out';
72
+ userId: string;
73
+ sessionId?: string;
74
+ tokenFamilyId?: string;
75
+ /** Every session and refresh-token family of the user. */
76
+ everywhere?: true;
77
+ }
78
+ /**
79
+ * Someone asked for a password reset link. `userId` is missing when no
80
+ * account has the address: nothing was sent. Many of those from one
81
+ * source is someone probing which addresses are registered.
82
+ */
83
+ export interface AuthenticationPasswordResetRequestedEvent {
84
+ type: 'password-reset-requested';
85
+ /** Trimmed and lowercased. */
86
+ email: string;
87
+ userId?: string;
88
+ }
89
+ /**
90
+ * A reset link set a new password. Every session and refresh-token family
91
+ * of the user was ended, and the address counts as verified.
92
+ */
93
+ export interface AuthenticationPasswordResetEvent {
94
+ type: 'password-reset';
95
+ userId: string;
96
+ }
97
+ /** A verification link proved the user's address. */
98
+ export interface AuthenticationEmailVerifiedEvent {
99
+ type: 'email-verified';
100
+ userId: string;
101
+ email: string;
102
+ }
103
+ /**
104
+ * A magic link came back and signed nobody in. `not-this-browser`: the
105
+ * browser holds no transaction cookie for this link (`MagicLinkService`
106
+ * sets one when the link is requested), so the link was opened somewhere
107
+ * else, on another device, or planted by whoever requested it (login CSRF);
108
+ * it stays usable where it was requested, and `consume()` threw a
109
+ * `MagicLinkError`. The others are its `null`: `unknown`: malformed, used,
110
+ * never issued, or presented with a cookie whose secret is not the link's.
111
+ * `expired`: past `magicLink.ttl`. `refused`:
112
+ * `MagicLinkHandler.resolveUser()` returned `null`, or an account whose
113
+ * stored address is not the one the link was sent to.
114
+ */
115
+ export interface AuthenticationMagicLinkRefusedEvent {
116
+ type: 'magic-link-refused';
117
+ reason: 'not-this-browser' | 'unknown' | 'expired' | 'refused';
118
+ /** The address the link was sent to, once the link was looked up (`expired`, `refused`). */
119
+ email?: string;
120
+ }
121
+ export type AuthenticationEvent = AuthenticationSignInEvent | AuthenticationSignOutEvent | AuthenticationMfaVerifiedEvent | AuthenticationMfaFailedEvent | AuthenticationMfaEnabledEvent | AuthenticationMfaDisabledEvent | AuthenticationRecoveryCodesGeneratedEvent | AuthenticationRefreshTokenReusedEvent | AuthenticationPasswordResetRequestedEvent | AuthenticationPasswordResetEvent | AuthenticationEmailVerifiedEvent | AuthenticationMagicLinkRefusedEvent;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,19 @@
1
+ import { type OnApplicationShutdown } from '@nestjs/common';
2
+ import { type Observable } from 'rxjs';
3
+ import type { AuthenticationEvent } from './authentication-events.interface.js';
4
+ /**
5
+ * The audit trail of sign-ins, sign-outs, second-factor changes, password
6
+ * resets, email verifications and refused magic links. Each event is also
7
+ * published on its `node:diagnostics_channel` channel
8
+ * (`nestjs:authentication:<type>`), for tooling that runs outside Nest.
9
+ * Listeners cannot change the outcome: a throwing channel subscriber is
10
+ * reported on the next tick, not in the sign-in that emitted.
11
+ */
12
+ export declare class AuthenticationEvents implements OnApplicationShutdown {
13
+ private readonly subject;
14
+ /** Every event of this application, in order. */
15
+ readonly events$: Observable<AuthenticationEvent>;
16
+ /** @internal Called by the module's services. */
17
+ emit(event: AuthenticationEvent): void;
18
+ onApplicationShutdown(): void;
19
+ }