@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,25 @@
1
+ import type { OidcTransaction } from './oidc.interface.js';
2
+ /**
3
+ * Storage for logins in progress (PKCE verifier, nonce, return path),
4
+ * keyed by `state`. Implement it on your database or Redis, and register
5
+ * the provider with `AuthenticationStorage.registerSource({ oidcStates: this })`.
6
+ *
7
+ * `consumeOidcState()` must be one atomic get-and-delete
8
+ * (`DELETE … RETURNING`, `GETDEL`), so a callback is accepted once. Anyone
9
+ * can start a login, so the store must stay bounded: drop expired logins
10
+ * as new ones are saved, and cap the rest.
11
+ */
12
+ export interface OidcStateStore {
13
+ /**
14
+ * Saves a new login (a fresh random `state`: a plain insert), then keeps
15
+ * the store bounded: deletes logins whose `expiresAt` is at or before this
16
+ * one's `createdAt`, and past a cap, those that expire first.
17
+ */
18
+ saveOidcState(transaction: OidcTransaction): Promise<void>;
19
+ /**
20
+ * Removes and returns the login, in one atomic step; `undefined` if there
21
+ * is none. Of several concurrent calls, exactly one gets the record.
22
+ * Expired logins may be returned: `OidcService` checks expiry.
23
+ */
24
+ consumeOidcState(state: string): Promise<OidcTransaction | undefined>;
25
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,84 @@
1
+ import type { CookieAttributes } from '../session/cookies.util.js';
2
+ import type { Duration } from './duration.interface.js';
3
+ import type { OidcProviderConfig } from './oidc-provider.interface.js';
4
+ export interface OidcTransaction {
5
+ state: string;
6
+ provider: string;
7
+ nonce?: string;
8
+ codeVerifier: string;
9
+ redirectTo?: string;
10
+ createdAt: Date;
11
+ expiresAt: Date;
12
+ /** Set for a link flow: the signed-in user (and their session id) who started it. */
13
+ link?: {
14
+ userId: string;
15
+ sessionId: string;
16
+ };
17
+ }
18
+ export interface OidcClientOptions {
19
+ fetch?: typeof fetch;
20
+ /** Clock in epoch milliseconds, for tests. */
21
+ now?: () => number;
22
+ /** How long a discovery document is trusted. Default `'1h'`. */
23
+ discoveryTtl?: Duration;
24
+ /** Leeway for ID token time claims. Default `'30s'`. */
25
+ clockTolerance?: Duration;
26
+ /** The providers' key sets: see `JwksClient`. */
27
+ jwks?: {
28
+ cacheTtl?: Duration;
29
+ cooldown?: Duration;
30
+ };
31
+ }
32
+ export interface OidcResolveContext {
33
+ /**
34
+ * Set when a signed-in user started the flow with `?link=true` ("connect
35
+ * your Google account"): attach the identity to this user, and refuse
36
+ * (throw, or return `null`) when it already belongs to someone else.
37
+ * The user's session was re-checked on the callback.
38
+ */
39
+ linkTo?: {
40
+ id: string;
41
+ };
42
+ }
43
+ export interface OidcOptions extends OidcClientOptions {
44
+ /**
45
+ * The public URL of your callback route, the redirect URI you register
46
+ * with each provider. `:provider` is replaced by the provider's name:
47
+ * `https://app.example.com/auth/oidc/:provider/callback`.
48
+ */
49
+ callbackUrl: string;
50
+ providers: Record<string, OidcProviderConfig>;
51
+ /** Where to land after sign-in when the login had no `redirectTo`. Default `/`. */
52
+ redirectAfterLogin?: string;
53
+ /** Lifetime of a login between the redirect to the provider and the callback. Default `'10m'`. */
54
+ transactionTtl?: Duration;
55
+ /**
56
+ * Attributes of the transaction cookie, `__Host-oidc_tx` (or `oidc_tx`
57
+ * when they rule the prefix out). `secure` defaults to `true`;
58
+ * `SameSite` is always `Lax`, which lets the cookie through the
59
+ * provider's redirect back.
60
+ */
61
+ cookie?: CookieAttributes;
62
+ }
63
+ /** The HTTP request of a login or callback, as Express and Fastify provide it. */
64
+ export type OidcRequest = {
65
+ headers: Record<string, string | string[] | undefined>;
66
+ method?: string;
67
+ };
68
+ /**
69
+ * Where to send the browser: return it from a handler decorated with
70
+ * `@Redirect()`. `cookies` are the `Set-Cookie` values the service already
71
+ * set on the HTTP response; send them yourself outside an HTTP handler.
72
+ */
73
+ export interface OidcRedirect {
74
+ url: string;
75
+ cookies: string[];
76
+ }
77
+ export interface OidcStartOptions {
78
+ /** A relative path to land on after signing in; anything else is ignored. */
79
+ redirectTo?: unknown;
80
+ /** Link the provider to the signed-in user ("connect your Google account") instead of signing in. */
81
+ link?: boolean;
82
+ /** The request, outside an HTTP handler (tests). Inside one, the service reads it. */
83
+ request?: OidcRequest;
84
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ /**
2
+ * scrypt parameters. The ones a stored hash names are bounded the same way,
3
+ * since a tampered row could otherwise demand any amount of memory: at most
4
+ * 1 GiB (128·N·r) and 16 times the default work (N·r·p).
5
+ */
6
+ export interface PasswordHasherOptions {
7
+ /** log2 of the scrypt cost N, an integer from 10 to 22. Default 17 (OWASP minimum: N=2^17, r=8, p=1; ~128 MiB). */
8
+ logN?: number;
9
+ /** Block size, 1 to 32. Default 8. */
10
+ r?: number;
11
+ /** Parallelism, 1 to 16. Default 1. */
12
+ p?: number;
13
+ /** Derived key length, 16 to 64 bytes. Default 32. */
14
+ keyLength?: number;
15
+ /** Salt length, 16 to 64 bytes. Default 16. */
16
+ saltLength?: number;
17
+ }
@@ -0,0 +1,49 @@
1
+ import type { Duration } from './duration.interface.js';
2
+ import type { IssuedSession } from './session.interface.js';
3
+ /** The account behind an address, as `PasswordResetHandler.findUser()` returns it. */
4
+ export interface PasswordResetAccount {
5
+ id: string;
6
+ /**
7
+ * The address the account has stored. The link goes there, never to the
8
+ * address typed in the form: a lookup that ignores accents or dots (MySQL's
9
+ * default collation does) would otherwise mail `victim@example.com`'s link
10
+ * to whoever typed `victim@exämple.com`. A link works only while the
11
+ * account keeps this address.
12
+ */
13
+ email: string;
14
+ /**
15
+ * The stored password hash, or `null` for an account without a password
16
+ * (a reset then sets one). A link only works while this is unchanged, so
17
+ * any password change invalidates the links sent before it.
18
+ */
19
+ passwordHash: string | null;
20
+ }
21
+ /** What `PasswordResetHandler.send()` delivers. */
22
+ export interface PasswordResetLink {
23
+ userId: string;
24
+ email: string;
25
+ /** `passwordReset.url` with `?token=…`. */
26
+ url: string;
27
+ expiresAt: Date;
28
+ }
29
+ export interface PasswordResetOptions {
30
+ /** Page that receives `?token=…`, asks for a new password and POSTs both, e.g. `https://app.example.com/reset-password`. */
31
+ url: string;
32
+ /** Lifetime of a link. Default `'1h'`. */
33
+ ttl?: Duration;
34
+ /** Clock in epoch milliseconds, for tests. */
35
+ now?: () => number;
36
+ }
37
+ export interface ResetPasswordOptions {
38
+ /**
39
+ * Signs the user in on this browser afterwards, through
40
+ * `SignInService.signIn()` (so a user with an authenticator gets a
41
+ * pending session). Default `false`.
42
+ */
43
+ signIn?: boolean;
44
+ }
45
+ export interface PasswordResetResult {
46
+ userId: string;
47
+ /** With `signIn: true`: the new session, as `SignInService.signIn()` returns it. */
48
+ signedIn?: IssuedSession;
49
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { Duration } from './duration.interface.js';
2
+ export interface RefreshTokenOptions {
3
+ /** Lifetime of one refresh token. Default `'30d'`. */
4
+ ttl?: Duration;
5
+ /** Maximum lifetime of a family, however often it rotates. Default `'90d'`. */
6
+ absoluteTtl?: Duration;
7
+ /** Clock in epoch milliseconds, for tests. */
8
+ now?: () => number;
9
+ }
10
+ export type RefreshTokenFailure = 'invalid' | 'expired' | 'reused';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ export interface RefreshTokenRecord {
2
+ /** SHA-256 of the token. */
3
+ id: string;
4
+ /** Every rotation stays in the family of the original sign-in. */
5
+ familyId: string;
6
+ userId: string;
7
+ createdAt: Date;
8
+ expiresAt: Date;
9
+ /** The family cannot be extended past this, however often it rotates. */
10
+ familyExpiresAt: Date;
11
+ usedAt?: Date;
12
+ /**
13
+ * Claims fixed at sign-in (`amr`, `auth_time`, …) that every token of the
14
+ * family carries, so access tokens minted on refresh describe the same
15
+ * authentication: a sign-in that passed MFA stays MFA-verified.
16
+ */
17
+ claims?: Record<string, unknown>;
18
+ }
19
+ /**
20
+ * Storage for refresh tokens. Implement it on your database or Redis, and
21
+ * register the provider with
22
+ * `AuthenticationStorage.registerSource({ refreshTokens: this })`.
23
+ *
24
+ * `markRefreshTokenUsed()` is what detects a stolen token, and must be one
25
+ * conditional write (`UPDATE … SET used_at = ? WHERE id = ? AND used_at IS
26
+ * NULL`), never a read followed by a write. A family's revocation must
27
+ * cover tokens saved *after* it: a refresh that lost the race to a reuse
28
+ * may still save its successor. Each method's comment has its rule, and
29
+ * `authenticationStoreContract()` from `@nestjs/authentication/testing`
30
+ * checks them.
31
+ *
32
+ * Optional fields come back absent (`undefined`), never `null`. Times come
33
+ * from `TokenService`'s clock, never the store's.
34
+ */
35
+ export interface RefreshTokenStore {
36
+ /** The token, or `undefined`. Used and expired tokens are returned too: `TokenService` checks them. */
37
+ getRefreshToken(id: string): Promise<RefreshTokenRecord | undefined>;
38
+ /**
39
+ * Saves a new token (a fresh random id: a plain insert). A good place to
40
+ * delete tokens whose `familyExpiresAt` has passed, so the store stays
41
+ * bounded (and with them their family's revocation, which no longer
42
+ * matters).
43
+ */
44
+ saveRefreshToken(record: RefreshTokenRecord): Promise<void>;
45
+ /**
46
+ * Sets `usedAt = at` iff the token exists and is unused, in one
47
+ * conditional write; `true` if this call did. Of several concurrent
48
+ * calls, exactly one gets `true`: the others are a reuse, and revoke the
49
+ * family.
50
+ */
51
+ markRefreshTokenUsed(id: string, at: Date): Promise<boolean>;
52
+ /**
53
+ * Revokes the family: `isRefreshTokenFamilyRevoked()` answers `true` from
54
+ * now on, including for tokens of the family saved later. Idempotent.
55
+ */
56
+ revokeRefreshTokenFamily(familyId: string): Promise<void>;
57
+ /** Whether the family was revoked (by `revokeRefreshTokenFamily()` or `revokeUserRefreshTokens()`). */
58
+ isRefreshTokenFamilyRevoked(familyId: string): Promise<boolean>;
59
+ /** Revokes every family the user has tokens in now. Families started later are not affected. */
60
+ revokeUserRefreshTokens(userId: string): Promise<void>;
61
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,53 @@
1
+ import type { MfaState } from './authentication-result.interface.js';
2
+ export interface SessionRecord {
3
+ /** SHA-256 of the cookie token. The token itself is never stored. */
4
+ id: string;
5
+ userId: string;
6
+ createdAt: Date;
7
+ /** Absolute expiry: activity never extends a session past this. */
8
+ expiresAt: Date;
9
+ /** Last activity, for the idle (sliding) timeout. */
10
+ lastActiveAt: Date;
11
+ mfa?: MfaState;
12
+ /** App data: user agent, IP, device name, for "your sessions" pages. */
13
+ metadata?: Record<string, unknown>;
14
+ }
15
+ /**
16
+ * Where sessions live. Implement it on your database or Redis, and register
17
+ * the provider with `AuthenticationStorage.registerSource({ sessions: this })`.
18
+ * Each method's comment has its rule, and `authenticationStoreContract()`
19
+ * from `@nestjs/authentication/testing` checks them.
20
+ *
21
+ * Optional fields come back absent (`undefined`), never `null`. Times come
22
+ * from `SessionService`'s clock, never the store's.
23
+ */
24
+ export interface SessionStore {
25
+ /** The session, or `undefined`. Expired sessions may be returned: `SessionService` checks expiry. */
26
+ getSession(id: string): Promise<SessionRecord | undefined>;
27
+ /**
28
+ * Saves a new session (a fresh random id: a plain insert). A good place
29
+ * to delete sessions whose `expiresAt` has passed, so the store stays
30
+ * bounded.
31
+ */
32
+ createSession(record: SessionRecord): Promise<void>;
33
+ /**
34
+ * Moves `lastActiveAt` forward, **only if the session still exists** and
35
+ * only forward: one conditional write, `UPDATE … SET last_active_at = ?
36
+ * WHERE id = ? AND last_active_at < ?`, `SET … XX` in Redis. A read
37
+ * followed by a write lets a request that read the session before a
38
+ * sign-out or rotation deleted it bring it back. Changes no other field.
39
+ */
40
+ touchSession(id: string, lastActiveAt: Date): Promise<void>;
41
+ /**
42
+ * Deletes the session, and resolves whether this call deleted it: one
43
+ * statement (`DELETE … WHERE id = ?` and its row count, Redis `DEL` and its
44
+ * count), `false` when it was already gone. `SessionService.rotate()`
45
+ * relies on it: of a rotation and a revocation of one session (or two
46
+ * rotations), only one may win.
47
+ */
48
+ deleteSession(id: string): Promise<boolean>;
49
+ /** The user's sessions, in any order (`[]` when none), expired ones included. */
50
+ listUserSessions(userId: string): Promise<SessionRecord[]>;
51
+ /** Deletes every session of the user ("sign out everywhere"). */
52
+ deleteUserSessions(userId: string): Promise<void>;
53
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,50 @@
1
+ import type { IncomingHttpHeaders } from 'node:http';
2
+ import type { CookieAttributes } from '../session/cookies.util.js';
3
+ import type { Duration } from './duration.interface.js';
4
+ import type { SessionRecord } from './session-store.interface.js';
5
+ /** The request a session is created from, as Express and Fastify both provide it. */
6
+ export interface SessionRequest {
7
+ headers: IncomingHttpHeaders;
8
+ ip?: string;
9
+ }
10
+ export interface SessionOptions {
11
+ /**
12
+ * Default `__Host-sid`, or `sid` when `cookie` rules the `__Host-` prefix
13
+ * out (`secure: false`, a `domain`, or a `path` other than `/`).
14
+ */
15
+ cookieName?: string;
16
+ /** Absolute lifetime: activity never extends a session past it. Default `'7d'`. */
17
+ absoluteTtl?: Duration;
18
+ /** Idle timeout, slid by activity. Default `'1d'`. `0` disables it. */
19
+ idleTtl?: Duration;
20
+ /** Write `lastActiveAt` at most this often, which saves a write per request. Default `'1m'`. */
21
+ touchInterval?: Duration;
22
+ /**
23
+ * `HttpOnly` is always set. `secure` defaults to `true`, which browsers
24
+ * accept from `http://localhost` too; turn it off only for plain HTTP on
25
+ * another host.
26
+ */
27
+ cookie?: CookieAttributes;
28
+ /**
29
+ * Origins besides the application's own whose pages may use the session
30
+ * cookie for unsafe requests (POST, …) and sign in, e.g.
31
+ * `['https://app.example.com']` for a web app on another origin than the
32
+ * API. The same list as `app.enableCsrfProtection({ trustedOrigins })`.
33
+ */
34
+ trustedOrigins?: string[];
35
+ /**
36
+ * What each new session stores next to the user, read from the request
37
+ * that signs in (password, magic link, OIDC alike): a user agent, an IP
38
+ * address, a device name, for "where you're signed in" pages.
39
+ */
40
+ metadata?: (request: SessionRequest) => Record<string, unknown>;
41
+ /** Clock in epoch milliseconds, for tests. */
42
+ now?: () => number;
43
+ }
44
+ export interface IssuedSession {
45
+ session: SessionRecord;
46
+ /** The raw token. Only the `Set-Cookie` value should leave the server. */
47
+ token: string;
48
+ /** `Set-Cookie` header value. `SignInService` sets it on the HTTP response itself. */
49
+ cookie: string;
50
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ export interface SignInOptions {
2
+ /**
3
+ * How the user proved who they are, recorded on the `sign-in` event:
4
+ * `password`, `magic-link`, `oidc:google`.
5
+ */
6
+ method?: string;
7
+ /** Stored with the session, over what `session.metadata` returns for the request. */
8
+ metadata?: Record<string, unknown>;
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ export interface IssueTokensOptions {
2
+ /**
3
+ * Claims that describe the sign-in (`amr`, `auth_time`, …): this access
4
+ * token and every one `refresh()` mints carry them. Keep roles and other
5
+ * facts that can change out of them: they are fixed for the family's life.
6
+ * The service owns the `amr` values that mean a second factor (`mfa`,
7
+ * `otp`, `hwk`): it adds `mfa` itself once a code was verified, and drops
8
+ * them from `claims.amr` with a warning (the rest, `pwd`, `sso`, is kept).
9
+ */
10
+ claims?: Record<string, unknown>;
11
+ /** How the user proved who they are, recorded on the `sign-in` event: `password`, `magic-link`. */
12
+ method?: string;
13
+ /**
14
+ * The code the client sent for a user with a confirmed authenticator: a
15
+ * TOTP `code` or a `recoveryCode`. Ignored for other users.
16
+ */
17
+ secondFactor?: {
18
+ code?: string;
19
+ recoveryCode?: string;
20
+ };
21
+ }
22
+ /** What a token endpoint returns to a client that signed in. */
23
+ export interface TokenPair {
24
+ /** A JWT signed with the `accessToken` options. */
25
+ accessToken: string;
26
+ /** Opaque, single use: `refresh()` exchanges it for a new pair. */
27
+ refreshToken: string;
28
+ /** Seconds until the access token expires (OAuth's `expires_in`). */
29
+ expiresIn: number;
30
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The `amr` values (RFC 8176) that mean a second factor was presented:
3
+ * `mfa` (what `TokenService` records), `otp` and `hwk`. `JwtBearerProvider`
4
+ * treats a token carrying one as MFA-verified, so `TokenService` never lets
5
+ * an app put one into a token by itself.
6
+ */
7
+ export declare const MFA_AMR_VALUES: readonly string[];
8
+ /** Whether an `amr` claim says a second factor was presented. */
9
+ export declare function hasMfaAmr(amr: unknown): boolean;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The `amr` values (RFC 8176) that mean a second factor was presented:
3
+ * `mfa` (what `TokenService` records), `otp` and `hwk`. `JwtBearerProvider`
4
+ * treats a token carrying one as MFA-verified, so `TokenService` never lets
5
+ * an app put one into a token by itself.
6
+ */
7
+ export const MFA_AMR_VALUES = ['mfa', 'otp', 'hwk'];
8
+ /** Whether an `amr` claim says a second factor was presented. */
9
+ export function hasMfaAmr(amr) {
10
+ return Array.isArray(amr) && amr.some((method) => typeof method === 'string' && MFA_AMR_VALUES.includes(method));
11
+ }
@@ -0,0 +1,29 @@
1
+ import type { RefreshTokenRecord, RefreshTokenStore } from '../interfaces/refresh-token-store.interface.js';
2
+ /**
3
+ * Process-local store: the default when no source is registered, and a
4
+ * test double. Families past their absolute expiry are dropped as new
5
+ * tokens are written, so an app that runs for months does not grow without
6
+ * bound.
7
+ */
8
+ export declare class InMemoryRefreshTokenStore implements RefreshTokenStore {
9
+ private readonly tokens;
10
+ private readonly revoked;
11
+ private sweepAt;
12
+ getRefreshToken(id: string): Promise<{
13
+ id: string;
14
+ familyId: string;
15
+ userId: string;
16
+ createdAt: Date;
17
+ expiresAt: Date;
18
+ familyExpiresAt: Date;
19
+ usedAt?: Date;
20
+ claims?: Record<string, unknown>;
21
+ } | undefined>;
22
+ saveRefreshToken(record: RefreshTokenRecord): Promise<void>;
23
+ markRefreshTokenUsed(id: string, at: Date): Promise<boolean>;
24
+ revokeRefreshTokenFamily(familyId: string): Promise<void>;
25
+ isRefreshTokenFamilyRevoked(familyId: string): Promise<boolean>;
26
+ revokeUserRefreshTokens(userId: string): Promise<void>;
27
+ /** Drops families past their absolute expiry (every token of a family shares it), and their revocation. */
28
+ private sweep;
29
+ }
@@ -0,0 +1,67 @@
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 { Injectable } from '@nestjs/common';
8
+ /**
9
+ * Process-local store: the default when no source is registered, and a
10
+ * test double. Families past their absolute expiry are dropped as new
11
+ * tokens are written, so an app that runs for months does not grow without
12
+ * bound.
13
+ */
14
+ let InMemoryRefreshTokenStore = class InMemoryRefreshTokenStore {
15
+ constructor() {
16
+ this.tokens = new Map();
17
+ this.revoked = new Set();
18
+ this.sweepAt = 1_024;
19
+ }
20
+ async getRefreshToken(id) {
21
+ const record = this.tokens.get(id);
22
+ return record && { ...record };
23
+ }
24
+ async saveRefreshToken(record) {
25
+ this.tokens.set(record.id, { ...record });
26
+ // The new token's own clock, so tests with a fake one agree.
27
+ if (this.tokens.size >= this.sweepAt) {
28
+ this.sweep(record.createdAt.getTime());
29
+ }
30
+ }
31
+ async markRefreshTokenUsed(id, at) {
32
+ const record = this.tokens.get(id);
33
+ if (!record || record.usedAt) {
34
+ return false;
35
+ }
36
+ record.usedAt = at;
37
+ return true;
38
+ }
39
+ async revokeRefreshTokenFamily(familyId) {
40
+ this.revoked.add(familyId);
41
+ }
42
+ async isRefreshTokenFamilyRevoked(familyId) {
43
+ return this.revoked.has(familyId);
44
+ }
45
+ async revokeUserRefreshTokens(userId) {
46
+ for (const record of this.tokens.values()) {
47
+ if (record.userId === userId) {
48
+ this.revoked.add(record.familyId);
49
+ }
50
+ }
51
+ }
52
+ /** Drops families past their absolute expiry (every token of a family shares it), and their revocation. */
53
+ sweep(now) {
54
+ for (const [id, record] of this.tokens) {
55
+ if (record.familyExpiresAt.getTime() > now) {
56
+ continue;
57
+ }
58
+ this.tokens.delete(id);
59
+ this.revoked.delete(record.familyId);
60
+ }
61
+ this.sweepAt = Math.max(1_024, this.tokens.size * 2);
62
+ }
63
+ };
64
+ InMemoryRefreshTokenStore = __decorate([
65
+ Injectable()
66
+ ], InMemoryRefreshTokenStore);
67
+ export { InMemoryRefreshTokenStore };
@@ -0,0 +1,34 @@
1
+ import { KeyObject } from 'node:crypto';
2
+ import type { JwksClientOptions } from '../interfaces/jwt-options.interface.js';
3
+ import { type JwsHeader } from './jws.util.js';
4
+ /**
5
+ * A cached JSON Web Key Set, shared by bearer-token verification and OIDC
6
+ * ID tokens.
7
+ *
8
+ * - Keys are cached for `cacheTtl`; an unknown `kid` triggers a refetch
9
+ * (key rotation), at most once per `cooldown`.
10
+ * - Concurrent refreshes share one request.
11
+ * - A failed refresh keeps serving the previous keys. With no keys to
12
+ * serve, it is an outage (a plain `Error`, so a 500, never a 401 that
13
+ * would make clients drop valid tokens), retried at most once per
14
+ * `cooldown`.
15
+ * - Keys marked `use` ≠ `sig`, with `key_ops` lacking `verify`, of
16
+ * unsupported types, or whose `alg` disagrees with the token are ignored.
17
+ */
18
+ export declare class JwksClient {
19
+ readonly uri: string;
20
+ private keys;
21
+ private fetchedAt;
22
+ private attemptedAt;
23
+ private failure?;
24
+ private inflight?;
25
+ private readonly options;
26
+ /** Number of network fetches, for tests and metrics. */
27
+ fetchCount: number;
28
+ constructor(uri: string, options?: JwksClientOptions);
29
+ getKey(header: Pick<JwsHeader, 'alg' | 'kid'>): Promise<KeyObject>;
30
+ private find;
31
+ private refresh;
32
+ private load;
33
+ private now;
34
+ }