@awesome-lang-auth/node 1.10.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 (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.detailed.md +4059 -0
  3. package/README.md +248 -0
  4. package/dist/abstract/base-auth-strategy.abstract.d.ts +7 -0
  5. package/dist/abstract/base-auth-strategy.abstract.d.ts.map +1 -0
  6. package/dist/abstract/base-auth-strategy.abstract.js +7 -0
  7. package/dist/abstract/base-auth-strategy.abstract.js.map +1 -0
  8. package/dist/abstract/base-oauth-strategy.abstract.d.ts +27 -0
  9. package/dist/abstract/base-oauth-strategy.abstract.d.ts.map +1 -0
  10. package/dist/abstract/base-oauth-strategy.abstract.js +11 -0
  11. package/dist/abstract/base-oauth-strategy.abstract.js.map +1 -0
  12. package/dist/adapters/express.d.ts +45 -0
  13. package/dist/adapters/express.d.ts.map +1 -0
  14. package/dist/adapters/express.js +49 -0
  15. package/dist/adapters/express.js.map +1 -0
  16. package/dist/adapters/fastify.d.ts +72 -0
  17. package/dist/adapters/fastify.d.ts.map +1 -0
  18. package/dist/adapters/fastify.js +63 -0
  19. package/dist/adapters/fastify.js.map +1 -0
  20. package/dist/auth-configurator.d.ts +65 -0
  21. package/dist/auth-configurator.d.ts.map +1 -0
  22. package/dist/auth-configurator.js +127 -0
  23. package/dist/auth-configurator.js.map +1 -0
  24. package/dist/events/auth-event-bus.d.ts +68 -0
  25. package/dist/events/auth-event-bus.d.ts.map +1 -0
  26. package/dist/events/auth-event-bus.js +60 -0
  27. package/dist/events/auth-event-bus.js.map +1 -0
  28. package/dist/events/auth-event-names.d.ts +34 -0
  29. package/dist/events/auth-event-names.d.ts.map +1 -0
  30. package/dist/events/auth-event-names.js +41 -0
  31. package/dist/events/auth-event-names.js.map +1 -0
  32. package/dist/http-types.d.ts +135 -0
  33. package/dist/http-types.d.ts.map +1 -0
  34. package/dist/http-types.js +18 -0
  35. package/dist/http-types.js.map +1 -0
  36. package/dist/index.d.ts +80 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +88 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/interfaces/api-key-store.interface.d.ts +94 -0
  41. package/dist/interfaces/api-key-store.interface.d.ts.map +1 -0
  42. package/dist/interfaces/api-key-store.interface.js +3 -0
  43. package/dist/interfaces/api-key-store.interface.js.map +1 -0
  44. package/dist/interfaces/auth-strategy.interface.d.ts +6 -0
  45. package/dist/interfaces/auth-strategy.interface.d.ts.map +1 -0
  46. package/dist/interfaces/auth-strategy.interface.js +3 -0
  47. package/dist/interfaces/auth-strategy.interface.js.map +1 -0
  48. package/dist/interfaces/linked-accounts-store.interface.d.ts +74 -0
  49. package/dist/interfaces/linked-accounts-store.interface.d.ts.map +1 -0
  50. package/dist/interfaces/linked-accounts-store.interface.js +3 -0
  51. package/dist/interfaces/linked-accounts-store.interface.js.map +1 -0
  52. package/dist/interfaces/pending-link-store.interface.d.ts +77 -0
  53. package/dist/interfaces/pending-link-store.interface.d.ts.map +1 -0
  54. package/dist/interfaces/pending-link-store.interface.js +3 -0
  55. package/dist/interfaces/pending-link-store.interface.js.map +1 -0
  56. package/dist/interfaces/roles-permissions-store.interface.d.ts +129 -0
  57. package/dist/interfaces/roles-permissions-store.interface.d.ts.map +1 -0
  58. package/dist/interfaces/roles-permissions-store.interface.js +3 -0
  59. package/dist/interfaces/roles-permissions-store.interface.js.map +1 -0
  60. package/dist/interfaces/session-store.interface.d.ts +92 -0
  61. package/dist/interfaces/session-store.interface.d.ts.map +1 -0
  62. package/dist/interfaces/session-store.interface.js +3 -0
  63. package/dist/interfaces/session-store.interface.js.map +1 -0
  64. package/dist/interfaces/settings-store.interface.d.ts +91 -0
  65. package/dist/interfaces/settings-store.interface.d.ts.map +1 -0
  66. package/dist/interfaces/settings-store.interface.js +3 -0
  67. package/dist/interfaces/settings-store.interface.js.map +1 -0
  68. package/dist/interfaces/sse-distributor.interface.d.ts +25 -0
  69. package/dist/interfaces/sse-distributor.interface.d.ts.map +1 -0
  70. package/dist/interfaces/sse-distributor.interface.js +3 -0
  71. package/dist/interfaces/sse-distributor.interface.js.map +1 -0
  72. package/dist/interfaces/telemetry-store.interface.d.ts +72 -0
  73. package/dist/interfaces/telemetry-store.interface.d.ts.map +1 -0
  74. package/dist/interfaces/telemetry-store.interface.js +3 -0
  75. package/dist/interfaces/telemetry-store.interface.js.map +1 -0
  76. package/dist/interfaces/template-store.interface.d.ts +37 -0
  77. package/dist/interfaces/template-store.interface.d.ts.map +1 -0
  78. package/dist/interfaces/template-store.interface.js +3 -0
  79. package/dist/interfaces/template-store.interface.js.map +1 -0
  80. package/dist/interfaces/tenant-store.interface.d.ts +97 -0
  81. package/dist/interfaces/tenant-store.interface.d.ts.map +1 -0
  82. package/dist/interfaces/tenant-store.interface.js +3 -0
  83. package/dist/interfaces/tenant-store.interface.js.map +1 -0
  84. package/dist/interfaces/token-store.interface.d.ts +10 -0
  85. package/dist/interfaces/token-store.interface.d.ts.map +1 -0
  86. package/dist/interfaces/token-store.interface.js +3 -0
  87. package/dist/interfaces/token-store.interface.js.map +1 -0
  88. package/dist/interfaces/user-metadata-store.interface.d.ts +50 -0
  89. package/dist/interfaces/user-metadata-store.interface.d.ts.map +1 -0
  90. package/dist/interfaces/user-metadata-store.interface.js +3 -0
  91. package/dist/interfaces/user-metadata-store.interface.js.map +1 -0
  92. package/dist/interfaces/user-store.interface.d.ts +113 -0
  93. package/dist/interfaces/user-store.interface.d.ts.map +1 -0
  94. package/dist/interfaces/user-store.interface.js +3 -0
  95. package/dist/interfaces/user-store.interface.js.map +1 -0
  96. package/dist/interfaces/webhook-store.interface.d.ts +139 -0
  97. package/dist/interfaces/webhook-store.interface.d.ts.map +1 -0
  98. package/dist/interfaces/webhook-store.interface.js +3 -0
  99. package/dist/interfaces/webhook-store.interface.js.map +1 -0
  100. package/dist/middleware/api-key.middleware.d.ts +35 -0
  101. package/dist/middleware/api-key.middleware.d.ts.map +1 -0
  102. package/dist/middleware/api-key.middleware.js +45 -0
  103. package/dist/middleware/api-key.middleware.js.map +1 -0
  104. package/dist/middleware/auth.middleware.d.ts +13 -0
  105. package/dist/middleware/auth.middleware.d.ts.map +1 -0
  106. package/dist/middleware/auth.middleware.js +55 -0
  107. package/dist/middleware/auth.middleware.js.map +1 -0
  108. package/dist/middleware/jwks-auth.middleware.d.ts +18 -0
  109. package/dist/middleware/jwks-auth.middleware.d.ts.map +1 -0
  110. package/dist/middleware/jwks-auth.middleware.js +77 -0
  111. package/dist/middleware/jwks-auth.middleware.js.map +1 -0
  112. package/dist/models/api-key.model.d.ts +66 -0
  113. package/dist/models/api-key.model.d.ts.map +1 -0
  114. package/dist/models/api-key.model.js +3 -0
  115. package/dist/models/api-key.model.js.map +1 -0
  116. package/dist/models/auth-config.model.d.ts +387 -0
  117. package/dist/models/auth-config.model.d.ts.map +1 -0
  118. package/dist/models/auth-config.model.js +3 -0
  119. package/dist/models/auth-config.model.js.map +1 -0
  120. package/dist/models/errors.d.ts +7 -0
  121. package/dist/models/errors.d.ts.map +1 -0
  122. package/dist/models/errors.js +14 -0
  123. package/dist/models/errors.js.map +1 -0
  124. package/dist/models/session.model.d.ts +28 -0
  125. package/dist/models/session.model.d.ts.map +1 -0
  126. package/dist/models/session.model.js +3 -0
  127. package/dist/models/session.model.js.map +1 -0
  128. package/dist/models/tenant.model.d.ts +20 -0
  129. package/dist/models/tenant.model.d.ts.map +1 -0
  130. package/dist/models/tenant.model.js +3 -0
  131. package/dist/models/tenant.model.js.map +1 -0
  132. package/dist/models/token.model.d.ts +21 -0
  133. package/dist/models/token.model.d.ts.map +1 -0
  134. package/dist/models/token.model.js +3 -0
  135. package/dist/models/token.model.js.map +1 -0
  136. package/dist/models/user.model.d.ts +92 -0
  137. package/dist/models/user.model.d.ts.map +1 -0
  138. package/dist/models/user.model.js +3 -0
  139. package/dist/models/user.model.js.map +1 -0
  140. package/dist/router/admin.router.d.ts +188 -0
  141. package/dist/router/admin.router.d.ts.map +1 -0
  142. package/dist/router/admin.router.js +1507 -0
  143. package/dist/router/admin.router.js.map +1 -0
  144. package/dist/router/auth.router.d.ts +199 -0
  145. package/dist/router/auth.router.d.ts.map +1 -0
  146. package/dist/router/auth.router.js +1636 -0
  147. package/dist/router/auth.router.js.map +1 -0
  148. package/dist/router/openapi.d.ts +98 -0
  149. package/dist/router/openapi.d.ts.map +1 -0
  150. package/dist/router/openapi.js +1518 -0
  151. package/dist/router/openapi.js.map +1 -0
  152. package/dist/router/router-events.d.ts +38 -0
  153. package/dist/router/router-events.d.ts.map +1 -0
  154. package/dist/router/router-events.js +74 -0
  155. package/dist/router/router-events.js.map +1 -0
  156. package/dist/router/tools.router.d.ts +104 -0
  157. package/dist/router/tools.router.d.ts.map +1 -0
  158. package/dist/router/tools.router.js +227 -0
  159. package/dist/router/tools.router.js.map +1 -0
  160. package/dist/router/ui.router.d.ts +49 -0
  161. package/dist/router/ui.router.d.ts.map +1 -0
  162. package/dist/router/ui.router.js +272 -0
  163. package/dist/router/ui.router.js.map +1 -0
  164. package/dist/services/api-key.service.d.ts +53 -0
  165. package/dist/services/api-key.service.d.ts.map +1 -0
  166. package/dist/services/api-key.service.js +66 -0
  167. package/dist/services/api-key.service.js.map +1 -0
  168. package/dist/services/jwks.service.d.ts +73 -0
  169. package/dist/services/jwks.service.d.ts.map +1 -0
  170. package/dist/services/jwks.service.js +174 -0
  171. package/dist/services/jwks.service.js.map +1 -0
  172. package/dist/services/mailer.service.d.ts +30 -0
  173. package/dist/services/mailer.service.d.ts.map +1 -0
  174. package/dist/services/mailer.service.js +248 -0
  175. package/dist/services/mailer.service.js.map +1 -0
  176. package/dist/services/notification.service.d.ts +110 -0
  177. package/dist/services/notification.service.d.ts.map +1 -0
  178. package/dist/services/notification.service.js +79 -0
  179. package/dist/services/notification.service.js.map +1 -0
  180. package/dist/services/password.service.d.ts +5 -0
  181. package/dist/services/password.service.d.ts.map +1 -0
  182. package/dist/services/password.service.js +17 -0
  183. package/dist/services/password.service.js.map +1 -0
  184. package/dist/services/sms.service.d.ts +14 -0
  185. package/dist/services/sms.service.d.ts.map +1 -0
  186. package/dist/services/sms.service.js +51 -0
  187. package/dist/services/sms.service.js.map +1 -0
  188. package/dist/services/token.service.d.ts +62 -0
  189. package/dist/services/token.service.d.ts.map +1 -0
  190. package/dist/services/token.service.js +354 -0
  191. package/dist/services/token.service.js.map +1 -0
  192. package/dist/stores/memory-template.store.d.ts +12 -0
  193. package/dist/stores/memory-template.store.d.ts.map +1 -0
  194. package/dist/stores/memory-template.store.js +35 -0
  195. package/dist/stores/memory-template.store.js.map +1 -0
  196. package/dist/strategies/api-key/api-key.strategy.d.ts +72 -0
  197. package/dist/strategies/api-key/api-key.strategy.d.ts.map +1 -0
  198. package/dist/strategies/api-key/api-key.strategy.js +182 -0
  199. package/dist/strategies/api-key/api-key.strategy.js.map +1 -0
  200. package/dist/strategies/local/local.strategy.d.ts +19 -0
  201. package/dist/strategies/local/local.strategy.d.ts.map +1 -0
  202. package/dist/strategies/local/local.strategy.js +45 -0
  203. package/dist/strategies/local/local.strategy.js.map +1 -0
  204. package/dist/strategies/magic-link/magic-link.strategy.d.ts +8 -0
  205. package/dist/strategies/magic-link/magic-link.strategy.d.ts.map +1 -0
  206. package/dist/strategies/magic-link/magic-link.strategy.js +53 -0
  207. package/dist/strategies/magic-link/magic-link.strategy.js.map +1 -0
  208. package/dist/strategies/oauth/generic-oauth.strategy.d.ts +120 -0
  209. package/dist/strategies/oauth/generic-oauth.strategy.d.ts.map +1 -0
  210. package/dist/strategies/oauth/generic-oauth.strategy.js +88 -0
  211. package/dist/strategies/oauth/generic-oauth.strategy.js.map +1 -0
  212. package/dist/strategies/oauth/github.strategy.d.ts +31 -0
  213. package/dist/strategies/oauth/github.strategy.d.ts.map +1 -0
  214. package/dist/strategies/oauth/github.strategy.js +72 -0
  215. package/dist/strategies/oauth/github.strategy.js.map +1 -0
  216. package/dist/strategies/oauth/google.strategy.d.ts +31 -0
  217. package/dist/strategies/oauth/google.strategy.d.ts.map +1 -0
  218. package/dist/strategies/oauth/google.strategy.js +61 -0
  219. package/dist/strategies/oauth/google.strategy.js.map +1 -0
  220. package/dist/strategies/sms/sms.strategy.d.ts +7 -0
  221. package/dist/strategies/sms/sms.strategy.d.ts.map +1 -0
  222. package/dist/strategies/sms/sms.strategy.js +39 -0
  223. package/dist/strategies/sms/sms.strategy.js.map +1 -0
  224. package/dist/strategies/two-factor/totp.strategy.d.ts +12 -0
  225. package/dist/strategies/two-factor/totp.strategy.d.ts.map +1 -0
  226. package/dist/strategies/two-factor/totp.strategy.js +32 -0
  227. package/dist/strategies/two-factor/totp.strategy.js.map +1 -0
  228. package/dist/tools/auth-tools.d.ts +200 -0
  229. package/dist/tools/auth-tools.d.ts.map +1 -0
  230. package/dist/tools/auth-tools.js +232 -0
  231. package/dist/tools/auth-tools.js.map +1 -0
  232. package/dist/tools/sse-manager.d.ts +118 -0
  233. package/dist/tools/sse-manager.d.ts.map +1 -0
  234. package/dist/tools/sse-manager.js +163 -0
  235. package/dist/tools/sse-manager.js.map +1 -0
  236. package/dist/tools/sse-notify.decorator.d.ts +74 -0
  237. package/dist/tools/sse-notify.decorator.d.ts.map +1 -0
  238. package/dist/tools/sse-notify.decorator.js +78 -0
  239. package/dist/tools/sse-notify.decorator.js.map +1 -0
  240. package/dist/tools/webhook-action.d.ts +130 -0
  241. package/dist/tools/webhook-action.d.ts.map +1 -0
  242. package/dist/tools/webhook-action.js +144 -0
  243. package/dist/tools/webhook-action.js.map +1 -0
  244. package/dist/tools/webhook-sender.d.ts +31 -0
  245. package/dist/tools/webhook-sender.d.ts.map +1 -0
  246. package/dist/tools/webhook-sender.js +80 -0
  247. package/dist/tools/webhook-sender.js.map +1 -0
  248. package/dist/ui-assets/2fa.html +115 -0
  249. package/dist/ui-assets/account-conflict.html +108 -0
  250. package/dist/ui-assets/admin.css +263 -0
  251. package/dist/ui-assets/admin.js +1927 -0
  252. package/dist/ui-assets/auth.js +725 -0
  253. package/dist/ui-assets/base.css +219 -0
  254. package/dist/ui-assets/forgot-password.html +93 -0
  255. package/dist/ui-assets/link-verify.html +74 -0
  256. package/dist/ui-assets/login.html +135 -0
  257. package/dist/ui-assets/magic-link.html +112 -0
  258. package/dist/ui-assets/register.html +122 -0
  259. package/dist/ui-assets/reset-password.html +103 -0
  260. package/dist/ui-assets/ui-i18n-keys.json +78 -0
  261. package/dist/ui-assets/verify-email.html +66 -0
  262. package/package.json +89 -0
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MemoryTemplateStore = void 0;
4
+ class MemoryTemplateStore {
5
+ constructor() {
6
+ this.mailTemplates = new Map();
7
+ this.uiTranslations = new Map();
8
+ }
9
+ async getMailTemplate(id) {
10
+ return this.mailTemplates.get(id) || null;
11
+ }
12
+ async listMailTemplates() {
13
+ return Array.from(this.mailTemplates.values());
14
+ }
15
+ async updateMailTemplate(id, template) {
16
+ const existing = this.mailTemplates.get(id) || {
17
+ id,
18
+ baseHtml: '',
19
+ baseText: '',
20
+ translations: {}
21
+ };
22
+ this.mailTemplates.set(id, { ...existing, ...template });
23
+ }
24
+ async getUiTranslations(page) {
25
+ return this.uiTranslations.get(page) || null;
26
+ }
27
+ async listUiTranslations() {
28
+ return Array.from(this.uiTranslations.values());
29
+ }
30
+ async updateUiTranslations(page, translations) {
31
+ this.uiTranslations.set(page, { page, translations });
32
+ }
33
+ }
34
+ exports.MemoryTemplateStore = MemoryTemplateStore;
35
+ //# sourceMappingURL=memory-template.store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-template.store.js","sourceRoot":"","sources":["../../src/stores/memory-template.store.ts"],"names":[],"mappings":";;;AAEA,MAAa,mBAAmB;IAAhC;QACY,kBAAa,GAA8B,IAAI,GAAG,EAAE,CAAC;QACrD,mBAAc,GAA+B,IAAI,GAAG,EAAE,CAAC;IA+BnE,CAAC;IA7BG,KAAK,CAAC,eAAe,CAAC,EAAU;QAC5B,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,iBAAiB;QACnB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,EAAU,EAAE,QAA+B;QAChE,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI;YAC3C,EAAE;YACF,QAAQ,EAAE,EAAE;YACZ,QAAQ,EAAE,EAAE;YACZ,YAAY,EAAE,EAAE;SACnB,CAAC;QACF,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,IAAY;QAChC,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,kBAAkB;QACpB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,IAAY,EAAE,YAAoD;QACzF,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;IAC1D,CAAC;CACJ;AAjCD,kDAiCC"}
@@ -0,0 +1,72 @@
1
+ import { IApiKeyStore } from '../../interfaces/api-key-store.interface';
2
+ import { ApiKeyContext } from '../../models/api-key.model';
3
+ /** Options that control how the strategy validates incoming requests. */
4
+ export interface ApiKeyStrategyOptions {
5
+ /**
6
+ * When `true`, `req.ip` (set by Express) is compared against the key's
7
+ * `allowedIps` list. If the IP is not on the list the request is rejected.
8
+ *
9
+ * @default true
10
+ */
11
+ enforceIpAllowlist?: boolean;
12
+ /**
13
+ * When provided, only keys that include **all** of the listed scopes are
14
+ * accepted. Use this to require specific capabilities at the middleware
15
+ * level.
16
+ *
17
+ * @example `['tools:read']`
18
+ */
19
+ requiredScopes?: string[];
20
+ /**
21
+ * When `true`, a usage entry is appended to the store's audit log after
22
+ * every authentication attempt (success or failure).
23
+ *
24
+ * @default false
25
+ */
26
+ auditLog?: boolean;
27
+ }
28
+ /**
29
+ * Stateless helper that validates API keys from an HTTP request.
30
+ *
31
+ * Accepted header formats (checked in order):
32
+ * 1. `Authorization: ApiKey <key>`
33
+ * 2. `X-Api-Key: <key>`
34
+ *
35
+ * Validation steps:
36
+ * 1. Extract the key from the header.
37
+ * 2. Find an active candidate record by prefix.
38
+ * 3. Verify the bcrypt hash.
39
+ * 4. Check expiry.
40
+ * 5. (Optional) Check IP allowlist.
41
+ * 6. (Optional) Check required scopes.
42
+ * 7. Update `lastUsedAt` + optional audit log.
43
+ */
44
+ export declare class ApiKeyStrategy {
45
+ private readonly store;
46
+ private readonly options;
47
+ constructor(store: IApiKeyStore, options?: ApiKeyStrategyOptions);
48
+ /**
49
+ * Extract and validate the API key from the provided headers and remote IP.
50
+ *
51
+ * @param headers HTTP request headers (`req.headers`).
52
+ * @param remoteIp Client IP address (`req.ip`).
53
+ * @returns The `ApiKeyContext` on success.
54
+ * @throws `AuthError` on any validation failure.
55
+ */
56
+ authenticate(headers: Record<string, string | string[] | undefined>, remoteIp?: string): Promise<ApiKeyContext>;
57
+ /**
58
+ * Extract the raw API key from the request headers.
59
+ * Accepts `Authorization: ApiKey <key>` and `X-Api-Key: <key>`.
60
+ */
61
+ private extractKey;
62
+ /**
63
+ * Check whether `ip` is contained in one of the `allowedIps` entries.
64
+ * Supports exact IPv4/IPv6 matches and CIDR notation for IPv4.
65
+ */
66
+ private isIpAllowed;
67
+ /** Simple IPv4 CIDR check. Returns false for IPv6 CIDRs (not supported). */
68
+ private ipInCidr;
69
+ private ipToNumber;
70
+ private appendAuditLog;
71
+ }
72
+ //# sourceMappingURL=api-key.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key.strategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/api-key/api-key.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAoB,MAAM,0CAA0C,CAAC;AAE1F,OAAO,EAAU,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGnE,yEAAyE;AACzE,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAYD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,KAAK,EAAE,YAAY,EACnB,OAAO,GAAE,qBAA0B;IAGtD;;;;;;;OAOG;IACG,YAAY,CAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EACtD,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC;IAqEzB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAYlB;;;OAGG;IACH,OAAO,CAAC,WAAW;IAYnB,4EAA4E;IAC5E,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,UAAU;YAYJ,cAAc;CAwB7B"}
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiKeyStrategy = void 0;
4
+ const api_key_service_1 = require("../../services/api-key.service");
5
+ const errors_1 = require("../../models/errors");
6
+ const apiKeyService = new api_key_service_1.ApiKeyService();
7
+ /**
8
+ * Dummy bcrypt hash used when no key record is found in the store.
9
+ * Running `verifyKey` against this hash ensures the bcrypt work factor is
10
+ * always paid — preventing timing attacks that could reveal whether a given
11
+ * key prefix exists in the database.
12
+ */
13
+ const TIMING_MITIGATION_DUMMY_HASH = '$2a$10$invalidhashpaddingtomitigatetiming0000000000000000000';
14
+ /**
15
+ * Stateless helper that validates API keys from an HTTP request.
16
+ *
17
+ * Accepted header formats (checked in order):
18
+ * 1. `Authorization: ApiKey <key>`
19
+ * 2. `X-Api-Key: <key>`
20
+ *
21
+ * Validation steps:
22
+ * 1. Extract the key from the header.
23
+ * 2. Find an active candidate record by prefix.
24
+ * 3. Verify the bcrypt hash.
25
+ * 4. Check expiry.
26
+ * 5. (Optional) Check IP allowlist.
27
+ * 6. (Optional) Check required scopes.
28
+ * 7. Update `lastUsedAt` + optional audit log.
29
+ */
30
+ class ApiKeyStrategy {
31
+ constructor(store, options = {}) {
32
+ this.store = store;
33
+ this.options = options;
34
+ }
35
+ /**
36
+ * Extract and validate the API key from the provided headers and remote IP.
37
+ *
38
+ * @param headers HTTP request headers (`req.headers`).
39
+ * @param remoteIp Client IP address (`req.ip`).
40
+ * @returns The `ApiKeyContext` on success.
41
+ * @throws `AuthError` on any validation failure.
42
+ */
43
+ async authenticate(headers, remoteIp) {
44
+ const rawKey = this.extractKey(headers);
45
+ if (!rawKey) {
46
+ throw new errors_1.AuthError('API key is required', 'API_KEY_MISSING', 401);
47
+ }
48
+ const prefix = apiKeyService.extractPrefix(rawKey);
49
+ const record = await this.store.findByPrefix(prefix);
50
+ // Always run bcrypt even when no record is found (timing-attack mitigation).
51
+ const hashToCompare = record?.keyHash ?? TIMING_MITIGATION_DUMMY_HASH;
52
+ const valid = await apiKeyService.verifyKey(rawKey, hashToCompare);
53
+ if (!valid || !record) {
54
+ await this.appendAuditLog(null, remoteIp, headers, false, 'INVALID_KEY');
55
+ throw new errors_1.AuthError('Invalid API key', 'API_KEY_INVALID', 401);
56
+ }
57
+ // Key must still be active
58
+ if (!record.isActive) {
59
+ await this.appendAuditLog(record, remoteIp, headers, false, 'KEY_REVOKED');
60
+ throw new errors_1.AuthError('API key has been revoked', 'API_KEY_REVOKED', 401);
61
+ }
62
+ // Expiry check
63
+ if (record.expiresAt && new Date() > record.expiresAt) {
64
+ await this.appendAuditLog(record, remoteIp, headers, false, 'KEY_EXPIRED');
65
+ throw new errors_1.AuthError('API key has expired', 'API_KEY_EXPIRED', 401);
66
+ }
67
+ // IP allowlist check
68
+ const enforceIp = this.options.enforceIpAllowlist !== false;
69
+ if (enforceIp && record.allowedIps && record.allowedIps.length > 0) {
70
+ if (!remoteIp || !this.isIpAllowed(remoteIp, record.allowedIps)) {
71
+ await this.appendAuditLog(record, remoteIp, headers, false, 'IP_NOT_ALLOWED');
72
+ throw new errors_1.AuthError('IP address not allowed for this API key', 'API_KEY_IP_BLOCKED', 403);
73
+ }
74
+ }
75
+ // Scope check
76
+ const requiredScopes = this.options.requiredScopes ?? [];
77
+ if (requiredScopes.length > 0) {
78
+ const keyScopes = record.scopes ?? [];
79
+ const missing = requiredScopes.filter((s) => !keyScopes.includes(s));
80
+ if (missing.length > 0) {
81
+ await this.appendAuditLog(record, remoteIp, headers, false, 'INSUFFICIENT_SCOPE');
82
+ throw new errors_1.AuthError(`API key missing required scopes: ${missing.join(', ')}`, 'API_KEY_INSUFFICIENT_SCOPE', 403);
83
+ }
84
+ }
85
+ // Success — update last-used timestamp and audit log
86
+ await this.store.updateLastUsed(record.id, new Date());
87
+ await this.appendAuditLog(record, remoteIp, headers, true);
88
+ return {
89
+ keyId: record.id,
90
+ keyPrefix: record.keyPrefix,
91
+ name: record.name,
92
+ serviceId: record.serviceId,
93
+ scopes: record.scopes ?? [],
94
+ };
95
+ }
96
+ // ── Private helpers ───────────────────────────────────────────────────────
97
+ /**
98
+ * Extract the raw API key from the request headers.
99
+ * Accepts `Authorization: ApiKey <key>` and `X-Api-Key: <key>`.
100
+ */
101
+ extractKey(headers) {
102
+ const authHeader = headers['authorization'];
103
+ if (typeof authHeader === 'string' && authHeader.startsWith('ApiKey ')) {
104
+ return authHeader.slice(7).trim() || null;
105
+ }
106
+ const xApiKey = headers['x-api-key'];
107
+ if (typeof xApiKey === 'string' && xApiKey.trim()) {
108
+ return xApiKey.trim();
109
+ }
110
+ return null;
111
+ }
112
+ /**
113
+ * Check whether `ip` is contained in one of the `allowedIps` entries.
114
+ * Supports exact IPv4/IPv6 matches and CIDR notation for IPv4.
115
+ */
116
+ isIpAllowed(ip, allowedIps) {
117
+ const normalized = ip.replace(/^::ffff:/, ''); // unwrap IPv4-mapped IPv6
118
+ for (const entry of allowedIps) {
119
+ if (entry.includes('/')) {
120
+ if (this.ipInCidr(normalized, entry))
121
+ return true;
122
+ }
123
+ else if (normalized === entry || ip === entry) {
124
+ return true;
125
+ }
126
+ }
127
+ return false;
128
+ }
129
+ /** Simple IPv4 CIDR check. Returns false for IPv6 CIDRs (not supported). */
130
+ ipInCidr(ip, cidr) {
131
+ try {
132
+ const [range, bitsStr] = cidr.split('/');
133
+ const bits = parseInt(bitsStr, 10);
134
+ if (isNaN(bits))
135
+ return false;
136
+ const ipNum = this.ipToNumber(ip);
137
+ const rangeNum = this.ipToNumber(range);
138
+ if (ipNum === null || rangeNum === null)
139
+ return false;
140
+ const mask = bits === 0 ? 0 : (~0 << (32 - bits)) >>> 0;
141
+ return (ipNum & mask) === (rangeNum & mask);
142
+ }
143
+ catch {
144
+ return false;
145
+ }
146
+ }
147
+ ipToNumber(ip) {
148
+ const parts = ip.split('.');
149
+ if (parts.length !== 4)
150
+ return null;
151
+ let num = 0;
152
+ for (const part of parts) {
153
+ const n = parseInt(part, 10);
154
+ if (isNaN(n) || n < 0 || n > 255)
155
+ return null;
156
+ num = (num << 8) | n;
157
+ }
158
+ return num >>> 0;
159
+ }
160
+ async appendAuditLog(record, ip, headers, success, failureReason) {
161
+ if (!this.options.auditLog || !this.store.logUsage)
162
+ return;
163
+ const entry = {
164
+ // When record is null (unknown key), use '<unknown>' so the attempt is
165
+ // still audited without blocking and without exposing internal state.
166
+ keyId: record?.id ?? '<unknown>',
167
+ timestamp: new Date(),
168
+ ip,
169
+ userAgent: typeof headers['user-agent'] === 'string' ? headers['user-agent'] : undefined,
170
+ success,
171
+ failureReason,
172
+ };
173
+ try {
174
+ await this.store.logUsage(entry);
175
+ }
176
+ catch {
177
+ // Audit log failures must never block the request
178
+ }
179
+ }
180
+ }
181
+ exports.ApiKeyStrategy = ApiKeyStrategy;
182
+ //# sourceMappingURL=api-key.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-key.strategy.js","sourceRoot":"","sources":["../../../src/strategies/api-key/api-key.strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { BaseAuthStrategy } from '../../abstract/base-auth-strategy.abstract';
2
+ import { AuthConfig } from '../../models/auth-config.model';
3
+ import { BaseUser } from '../../models/user.model';
4
+ import { IUserStore } from '../../interfaces/user-store.interface';
5
+ import { PasswordService } from '../../services/password.service';
6
+ export declare class LocalStrategy extends BaseAuthStrategy<{
7
+ email: string;
8
+ password: string;
9
+ }, BaseUser> {
10
+ private readonly userStore;
11
+ private readonly passwordService;
12
+ name: string;
13
+ constructor(userStore: IUserStore, passwordService: PasswordService);
14
+ authenticate(input: {
15
+ email: string;
16
+ password: string;
17
+ }, config: AuthConfig): Promise<BaseUser>;
18
+ }
19
+ //# sourceMappingURL=local.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.strategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/local/local.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,4CAA4C,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAGlE,qBAAa,aAAc,SAAQ,gBAAgB,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAAE,QAAQ,CAAC;IAI9F,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAJlC,IAAI,SAAW;gBAGI,SAAS,EAAE,UAAU,EACrB,eAAe,EAAE,eAAe;IAK7C,YAAY,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;CAiCtG"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LocalStrategy = void 0;
4
+ const base_auth_strategy_abstract_1 = require("../../abstract/base-auth-strategy.abstract");
5
+ const errors_1 = require("../../models/errors");
6
+ class LocalStrategy extends base_auth_strategy_abstract_1.BaseAuthStrategy {
7
+ constructor(userStore, passwordService) {
8
+ super();
9
+ this.userStore = userStore;
10
+ this.passwordService = passwordService;
11
+ this.name = 'local';
12
+ }
13
+ async authenticate(input, config) {
14
+ const user = await this.userStore.findByEmail(input.email);
15
+ if (!user) {
16
+ throw new errors_1.AuthError('Invalid credentials', 'INVALID_CREDENTIALS', 401);
17
+ }
18
+ if (!user.password) {
19
+ throw new errors_1.AuthError('Invalid credentials', 'INVALID_CREDENTIALS', 401);
20
+ }
21
+ const valid = await this.passwordService.compare(input.password, user.password);
22
+ if (!valid) {
23
+ throw new errors_1.AuthError('Invalid credentials', 'INVALID_CREDENTIALS', 401);
24
+ }
25
+ // Determine effective email-verification mode.
26
+ // `emailVerificationMode` takes precedence; fall back to the legacy boolean.
27
+ const verificationMode = config.emailVerificationMode ??
28
+ (config.requireEmailVerification ? 'strict' : 'none');
29
+ if (!user.isEmailVerified) {
30
+ if (verificationMode === 'strict') {
31
+ throw new errors_1.AuthError('Email address is not verified', 'EMAIL_NOT_VERIFIED', 403);
32
+ }
33
+ else if (verificationMode === 'lazy') {
34
+ // Block only after the grace-period deadline has passed.
35
+ if (user.emailVerificationDeadline && new Date() > user.emailVerificationDeadline) {
36
+ throw new errors_1.AuthError('Email verification required', 'EMAIL_VERIFICATION_REQUIRED', 403);
37
+ }
38
+ }
39
+ // 'none' → fall through, allow login
40
+ }
41
+ return user;
42
+ }
43
+ }
44
+ exports.LocalStrategy = LocalStrategy;
45
+ //# sourceMappingURL=local.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.strategy.js","sourceRoot":"","sources":["../../../src/strategies/local/local.strategy.ts"],"names":[],"mappings":";;;AAAA,4FAA8E;AAK9E,gDAAgD;AAEhD,MAAa,aAAc,SAAQ,8CAA+D;IAGhG,YACmB,SAAqB,EACrB,eAAgC;QAEjD,KAAK,EAAE,CAAC;QAHS,cAAS,GAAT,SAAS,CAAY;QACrB,oBAAe,GAAf,eAAe,CAAiB;QAJnD,SAAI,GAAG,OAAO,CAAC;IAOf,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAA0C,EAAE,MAAkB;QAC/E,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC3D,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,kBAAS,CAAC,qBAAqB,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,kBAAS,CAAC,qBAAqB,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC;QACzE,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,kBAAS,CAAC,qBAAqB,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC;QACzE,CAAC;QAED,+CAA+C;QAC/C,6EAA6E;QAC7E,MAAM,gBAAgB,GACpB,MAAM,CAAC,qBAAqB;YAC5B,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAExD,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YAC1B,IAAI,gBAAgB,KAAK,QAAQ,EAAE,CAAC;gBAClC,MAAM,IAAI,kBAAS,CAAC,+BAA+B,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;YAClF,CAAC;iBAAM,IAAI,gBAAgB,KAAK,MAAM,EAAE,CAAC;gBACvC,yDAAyD;gBACzD,IAAI,IAAI,CAAC,yBAAyB,IAAI,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,yBAAyB,EAAE,CAAC;oBAClF,MAAM,IAAI,kBAAS,CAAC,6BAA6B,EAAE,6BAA6B,EAAE,GAAG,CAAC,CAAC;gBACzF,CAAC;YACH,CAAC;YACD,qCAAqC;QACvC,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA3CD,sCA2CC"}
@@ -0,0 +1,8 @@
1
+ import { IUserStore } from '../../interfaces/user-store.interface';
2
+ import { AuthConfig } from '../../models/auth-config.model';
3
+ import { BaseUser } from '../../models/user.model';
4
+ export declare class MagicLinkStrategy {
5
+ sendMagicLink(email: string, userStore: IUserStore, config: AuthConfig, lang?: string, siteUrlOverride?: string): Promise<void>;
6
+ verify(token: string, userStore: IUserStore): Promise<BaseUser>;
7
+ }
8
+ //# sourceMappingURL=magic-link.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"magic-link.strategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/magic-link/magic-link.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAOnD,qBAAa,iBAAiB;IACtB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB/H,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC;CAiBtE"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MagicLinkStrategy = void 0;
4
+ const token_service_1 = require("../../services/token.service");
5
+ const mailer_service_1 = require("../../services/mailer.service");
6
+ const errors_1 = require("../../models/errors");
7
+ const tokenService = new token_service_1.TokenService();
8
+ class MagicLinkStrategy {
9
+ async sendMagicLink(email, userStore, config, lang, siteUrlOverride) {
10
+ if (!config.email?.sendMagicLink && !config.email?.mailer) {
11
+ throw new errors_1.AuthError('Email not configured', 'EMAIL_NOT_CONFIGURED', 500);
12
+ }
13
+ const user = await userStore.findByEmail(email);
14
+ if (!user) {
15
+ // Don't reveal whether email exists
16
+ return;
17
+ }
18
+ const token = tokenService.generateSecureToken();
19
+ const expiry = new Date(Date.now() + 15 * 60 * 1000); // 15 min
20
+ await userStore.updateMagicLinkToken(user.id, token, expiry);
21
+ const siteUrlCfg = config.email?.siteUrl;
22
+ const defaultSiteUrl = Array.isArray(siteUrlCfg) ? (siteUrlCfg[0] ?? '') : (siteUrlCfg ?? '');
23
+ const basePath = siteUrlOverride || `${defaultSiteUrl}/auth`;
24
+ const cleanBasePath = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;
25
+ const link = `${cleanBasePath}/magic-link/verify?token=${token}`;
26
+ if (config.email?.sendMagicLink) {
27
+ await config.email.sendMagicLink(email, token, link, lang);
28
+ }
29
+ else if (config.email?.mailer) {
30
+ const mailer = new mailer_service_1.MailerService(config.email.mailer, config.templateStore);
31
+ await mailer.sendMagicLink(email, token, link, lang);
32
+ }
33
+ }
34
+ async verify(token, userStore) {
35
+ if (!userStore.findByMagicLinkToken) {
36
+ throw new errors_1.AuthError('UserStore does not implement findByMagicLinkToken', 'NOT_IMPLEMENTED', 500);
37
+ }
38
+ const user = await userStore.findByMagicLinkToken(token);
39
+ if (!user) {
40
+ throw new errors_1.AuthError('Invalid magic link token', 'INVALID_MAGIC_LINK', 401);
41
+ }
42
+ if (!user.magicLinkToken || user.magicLinkToken !== token) {
43
+ throw new errors_1.AuthError('Invalid magic link token', 'INVALID_MAGIC_LINK', 401);
44
+ }
45
+ if (user.magicLinkTokenExpiry && new Date() > user.magicLinkTokenExpiry) {
46
+ throw new errors_1.AuthError('Magic link token has expired', 'MAGIC_LINK_EXPIRED', 401);
47
+ }
48
+ await userStore.updateMagicLinkToken(user.id, null, null);
49
+ return user;
50
+ }
51
+ }
52
+ exports.MagicLinkStrategy = MagicLinkStrategy;
53
+ //# sourceMappingURL=magic-link.strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"magic-link.strategy.js","sourceRoot":"","sources":["../../../src/strategies/magic-link/magic-link.strategy.ts"],"names":[],"mappings":";;;AAGA,gEAA4D;AAC5D,kEAA8D;AAC9D,gDAAgD;AAEhD,MAAM,YAAY,GAAG,IAAI,4BAAY,EAAE,CAAC;AAExC,MAAa,iBAAiB;IAC5B,KAAK,CAAC,aAAa,CAAC,KAAa,EAAE,SAAqB,EAAE,MAAkB,EAAE,IAAa,EAAE,eAAwB;QACnH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;YAC1D,MAAM,IAAI,kBAAS,CAAC,sBAAsB,EAAE,sBAAsB,EAAE,GAAG,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,oCAAoC;YACpC,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,YAAY,CAAC,mBAAmB,EAAE,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS;QAC/D,MAAM,SAAS,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC7D,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC;QACzC,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QAC9F,MAAM,QAAQ,GAAG,eAAe,IAAI,GAAG,cAAc,OAAO,CAAC;QAC7D,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAChF,MAAM,IAAI,GAAG,GAAG,aAAa,4BAA4B,KAAK,EAAE,CAAC;QACjE,IAAI,MAAM,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC;YAChC,MAAM,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC7D,CAAC;aAAM,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,IAAI,8BAAa,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;YAC5E,MAAM,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,SAAqB;QAC/C,IAAI,CAAC,SAAS,CAAC,oBAAoB,EAAE,CAAC;YACpC,MAAM,IAAI,kBAAS,CAAC,mDAAmD,EAAE,iBAAiB,EAAE,GAAG,CAAC,CAAC;QACnG,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;QACzD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,kBAAS,CAAC,0BAA0B,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc,KAAK,KAAK,EAAE,CAAC;YAC1D,MAAM,IAAI,kBAAS,CAAC,0BAA0B,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,IAAI,CAAC,oBAAoB,IAAI,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;YACxE,MAAM,IAAI,kBAAS,CAAC,8BAA8B,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;QACjF,CAAC;QACD,MAAM,SAAS,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA3CD,8CA2CC"}
@@ -0,0 +1,120 @@
1
+ import { BaseOAuthStrategy } from '../../abstract/base-oauth-strategy.abstract';
2
+ import { BaseUser } from '../../models/user.model';
3
+ /**
4
+ * Configuration for a generic OAuth 2.0 provider.
5
+ *
6
+ * Use this to implement OAuth login for any provider that follows the
7
+ * standard OAuth 2.0 Authorization Code flow with a JSON user-info endpoint.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { GenericOAuthStrategy, GenericOAuthProviderConfig } from '@awesome-lang-auth/node';
12
+ *
13
+ * const microsoftConfig: GenericOAuthProviderConfig = {
14
+ * name: 'microsoft',
15
+ * clientId: process.env.MS_CLIENT_ID!,
16
+ * clientSecret: process.env.MS_CLIENT_SECRET!,
17
+ * callbackUrl: 'https://yourapp.com/auth/oauth/microsoft/callback',
18
+ * authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
19
+ * tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
20
+ * userInfoUrl: 'https://graph.microsoft.com/v1.0/me',
21
+ * scope: 'openid email profile',
22
+ * mapProfile: (data) => ({
23
+ * id: data.id,
24
+ * email: data.mail ?? data.userPrincipalName,
25
+ * name: data.displayName,
26
+ * }),
27
+ * };
28
+ *
29
+ * class MicrosoftStrategy extends GenericOAuthStrategy {
30
+ * async findOrCreateUser(profile) {
31
+ * return userStore.findOrCreate({ provider: 'microsoft', ...profile });
32
+ * }
33
+ * }
34
+ * const msStrategy = new MicrosoftStrategy(microsoftConfig);
35
+ * ```
36
+ */
37
+ export interface GenericOAuthProviderConfig {
38
+ /** Provider identifier, e.g. `'microsoft'`, `'facebook'`, `'discord'`. */
39
+ name: string;
40
+ /** OAuth application client ID. */
41
+ clientId: string;
42
+ /** OAuth application client secret. */
43
+ clientSecret: string;
44
+ /** Full URL where the provider redirects back after authorization. */
45
+ callbackUrl: string;
46
+ /** Provider's OAuth authorization endpoint URL. */
47
+ authorizationUrl: string;
48
+ /** Provider's token exchange endpoint URL. */
49
+ tokenUrl: string;
50
+ /** Provider's user-info (profile) endpoint URL. */
51
+ userInfoUrl: string;
52
+ /**
53
+ * Space-separated scope string (e.g. `'openid email profile'`) or an
54
+ * array of scope strings (joined with a space).
55
+ */
56
+ scope: string | string[];
57
+ /**
58
+ * Optional additional query parameters to append to the authorization URL.
59
+ * Useful for provider-specific parameters such as `access_type`, `prompt`, etc.
60
+ */
61
+ additionalAuthParams?: Record<string, string>;
62
+ /**
63
+ * Map the raw JSON profile returned by `userInfoUrl` to the normalized
64
+ * profile shape expected by `findOrCreateUser`.
65
+ *
66
+ * When omitted, the library assumes the profile already contains `id` and
67
+ * `email` fields at the top level.
68
+ */
69
+ mapProfile?: (raw: Record<string, unknown>) => {
70
+ id: string;
71
+ email: string;
72
+ emailVerified?: boolean;
73
+ name?: string;
74
+ picture?: string;
75
+ };
76
+ }
77
+ /**
78
+ * Generic OAuth 2.0 strategy.
79
+ *
80
+ * Extend this class to add OAuth login support for any provider that
81
+ * follows the standard Authorization Code flow with a JSON user-info
82
+ * endpoint. Only `findOrCreateUser` needs to be implemented.
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * class MicrosoftStrategy extends GenericOAuthStrategy<MyUser> {
87
+ * async findOrCreateUser(profile) {
88
+ * let user = await userStore.findByProviderAccount('microsoft', profile.id);
89
+ * if (!user) user = await userStore.create({ email: profile.email, loginProvider: 'microsoft' });
90
+ * return user as MyUser;
91
+ * }
92
+ * }
93
+ * ```
94
+ */
95
+ export declare abstract class GenericOAuthStrategy<TUser extends BaseUser = BaseUser> extends BaseOAuthStrategy<TUser> {
96
+ readonly name: string;
97
+ private readonly config;
98
+ constructor(config: GenericOAuthProviderConfig);
99
+ getAuthorizationUrl(state?: string): string;
100
+ protected exchangeCodeForTokens(code: string): Promise<{
101
+ accessToken: string;
102
+ idToken?: string;
103
+ }>;
104
+ protected getUserProfile(accessToken: string): Promise<{
105
+ id: string;
106
+ email: string;
107
+ emailVerified?: boolean;
108
+ name?: string;
109
+ picture?: string;
110
+ }>;
111
+ handleCallback(code: string, state?: string): Promise<TUser>;
112
+ abstract findOrCreateUser(profile: {
113
+ id: string;
114
+ email: string;
115
+ emailVerified?: boolean;
116
+ name?: string;
117
+ picture?: string;
118
+ }, state?: string): Promise<TUser>;
119
+ }
120
+ //# sourceMappingURL=generic-oauth.strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generic-oauth.strategy.d.ts","sourceRoot":"","sources":["../../../src/strategies/oauth/generic-oauth.strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,WAAW,0BAA0B;IACzC,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,gBAAgB,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK;QAC7C,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,8BAAsB,oBAAoB,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ,CAAE,SAAQ,iBAAiB,CAAC,KAAK,CAAC;IAC5G,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;gBAExC,MAAM,EAAE,0BAA0B;IAM9C,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;cAe3B,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;cAmBvF,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAoB/I,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAMlE,QAAQ,CAAC,gBAAgB,CACvB,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAChG,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,KAAK,CAAC;CAClB"}