firebase-admin-edge 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (437) hide show
  1. package/README.md +102 -261
  2. package/dist/app-check/app-check-endpoints.d.ts +31 -0
  3. package/dist/app-check/app-check-endpoints.d.ts.map +1 -0
  4. package/dist/app-check/app-check-endpoints.js +75 -0
  5. package/dist/app-check/app-check-endpoints.js.map +1 -0
  6. package/dist/app-check/app-check-jwt.d.ts +16 -0
  7. package/dist/app-check/app-check-jwt.d.ts.map +1 -0
  8. package/dist/app-check/app-check-jwt.js +59 -0
  9. package/dist/app-check/app-check-jwt.js.map +1 -0
  10. package/dist/app-check/app-check.d.ts +43 -0
  11. package/dist/app-check/app-check.d.ts.map +1 -0
  12. package/dist/app-check/app-check.js +141 -0
  13. package/dist/app-check/app-check.js.map +1 -0
  14. package/dist/auth/auth-blocking-types.d.ts +44 -0
  15. package/dist/auth/auth-blocking-types.d.ts.map +1 -0
  16. package/dist/auth/auth-blocking-types.js +2 -0
  17. package/dist/auth/auth-blocking-types.js.map +1 -0
  18. package/dist/auth/auth-config-types.d.ts +146 -0
  19. package/dist/auth/auth-config-types.d.ts.map +1 -0
  20. package/dist/auth/auth-config-types.js +2 -0
  21. package/dist/auth/auth-config-types.js.map +1 -0
  22. package/dist/auth/auth-config.d.ts +15 -0
  23. package/dist/auth/auth-config.d.ts.map +1 -0
  24. package/dist/auth/auth-config.js +413 -0
  25. package/dist/auth/auth-config.js.map +1 -0
  26. package/dist/auth/auth-emulator.d.ts +7 -0
  27. package/dist/auth/auth-emulator.d.ts.map +1 -0
  28. package/dist/auth/auth-emulator.js +24 -0
  29. package/dist/auth/auth-emulator.js.map +1 -0
  30. package/dist/auth/auth-endpoint-errors.d.ts +2 -0
  31. package/dist/auth/auth-endpoint-errors.d.ts.map +1 -1
  32. package/dist/auth/auth-endpoint-errors.js +20 -1
  33. package/dist/auth/auth-endpoint-errors.js.map +1 -1
  34. package/dist/auth/email-link.d.ts +24 -0
  35. package/dist/auth/email-link.d.ts.map +1 -0
  36. package/dist/auth/email-link.js +103 -0
  37. package/dist/auth/email-link.js.map +1 -0
  38. package/dist/auth/firebase-admin-auth.d.ts +29 -4
  39. package/dist/auth/firebase-admin-auth.d.ts.map +1 -1
  40. package/dist/auth/firebase-admin-auth.js +192 -59
  41. package/dist/auth/firebase-admin-auth.js.map +1 -1
  42. package/dist/auth/firebase-auth-endpoints.d.ts +64 -5
  43. package/dist/auth/firebase-auth-endpoints.d.ts.map +1 -1
  44. package/dist/auth/firebase-auth-endpoints.js +258 -73
  45. package/dist/auth/firebase-auth-endpoints.js.map +1 -1
  46. package/dist/auth/firebase-auth.d.ts +78 -4
  47. package/dist/auth/firebase-auth.d.ts.map +1 -1
  48. package/dist/auth/firebase-auth.js +101 -8
  49. package/dist/auth/firebase-auth.js.map +1 -1
  50. package/dist/auth/firebase-jwt.d.ts +19 -10
  51. package/dist/auth/firebase-jwt.d.ts.map +1 -1
  52. package/dist/auth/firebase-jwt.js +176 -39
  53. package/dist/auth/firebase-jwt.js.map +1 -1
  54. package/dist/auth/firebase-types.d.ts +3 -0
  55. package/dist/auth/firebase-types.d.ts.map +1 -1
  56. package/dist/auth/google-oauth.d.ts +0 -1
  57. package/dist/auth/google-oauth.d.ts.map +1 -1
  58. package/dist/auth/google-oauth.js +16 -86
  59. package/dist/auth/google-oauth.js.map +1 -1
  60. package/dist/auth/project-config-manager.d.ts +10 -0
  61. package/dist/auth/project-config-manager.d.ts.map +1 -0
  62. package/dist/auth/project-config-manager.js +22 -0
  63. package/dist/auth/project-config-manager.js.map +1 -0
  64. package/dist/auth/provider-credential.d.ts +43 -0
  65. package/dist/auth/provider-credential.d.ts.map +1 -0
  66. package/dist/auth/provider-credential.js +107 -0
  67. package/dist/auth/provider-credential.js.map +1 -0
  68. package/dist/auth/provider-session.d.ts +10 -0
  69. package/dist/auth/provider-session.d.ts.map +1 -0
  70. package/dist/auth/provider-session.js +28 -0
  71. package/dist/auth/provider-session.js.map +1 -0
  72. package/dist/auth/tenant-manager.d.ts +17 -0
  73. package/dist/auth/tenant-manager.d.ts.map +1 -0
  74. package/dist/auth/tenant-manager.js +59 -0
  75. package/dist/auth/tenant-manager.js.map +1 -0
  76. package/dist/db/aggregate.d.ts +49 -0
  77. package/dist/db/aggregate.d.ts.map +1 -0
  78. package/dist/db/aggregate.js +115 -0
  79. package/dist/db/aggregate.js.map +1 -0
  80. package/dist/db/bulk-writer.d.ts +55 -0
  81. package/dist/db/bulk-writer.d.ts.map +1 -0
  82. package/dist/db/bulk-writer.js +257 -0
  83. package/dist/db/bulk-writer.js.map +1 -0
  84. package/dist/db/bundle-builder.d.ts +17 -0
  85. package/dist/db/bundle-builder.d.ts.map +1 -0
  86. package/dist/db/bundle-builder.js +118 -0
  87. package/dist/db/bundle-builder.js.map +1 -0
  88. package/dist/db/bytes.d.ts +12 -0
  89. package/dist/db/bytes.d.ts.map +1 -0
  90. package/dist/db/bytes.js +49 -0
  91. package/dist/db/bytes.js.map +1 -0
  92. package/dist/db/collection-group.d.ts +14 -0
  93. package/dist/db/collection-group.d.ts.map +1 -0
  94. package/dist/db/collection-group.js +43 -0
  95. package/dist/db/collection-group.js.map +1 -0
  96. package/dist/db/collection-reference.d.ts +21 -0
  97. package/dist/db/collection-reference.d.ts.map +1 -0
  98. package/dist/db/collection-reference.js +46 -0
  99. package/dist/db/collection-reference.js.map +1 -0
  100. package/dist/db/document-reference.d.ts +41 -0
  101. package/dist/db/document-reference.d.ts.map +1 -0
  102. package/dist/db/document-reference.js +125 -0
  103. package/dist/db/document-reference.js.map +1 -0
  104. package/dist/db/document-snapshot.d.ts +31 -0
  105. package/dist/db/document-snapshot.d.ts.map +1 -0
  106. package/dist/db/document-snapshot.js +103 -0
  107. package/dist/db/document-snapshot.js.map +1 -0
  108. package/dist/db/explain.d.ts +28 -0
  109. package/dist/db/explain.d.ts.map +1 -0
  110. package/dist/db/explain.js +61 -0
  111. package/dist/db/explain.js.map +1 -0
  112. package/dist/db/field-path.d.ts +10 -0
  113. package/dist/db/field-path.d.ts.map +1 -0
  114. package/dist/db/field-path.js +65 -0
  115. package/dist/db/field-path.js.map +1 -0
  116. package/dist/db/field-value.d.ts +17 -0
  117. package/dist/db/field-value.d.ts.map +1 -0
  118. package/dist/db/field-value.js +57 -0
  119. package/dist/db/field-value.js.map +1 -0
  120. package/dist/db/filter.d.ts +20 -0
  121. package/dist/db/filter.d.ts.map +1 -0
  122. package/dist/db/filter.js +48 -0
  123. package/dist/db/filter.js.map +1 -0
  124. package/dist/db/firestore-converter.d.ts +11 -0
  125. package/dist/db/firestore-converter.d.ts.map +1 -0
  126. package/dist/db/firestore-converter.js +14 -0
  127. package/dist/db/firestore-converter.js.map +1 -0
  128. package/dist/db/firestore-document.d.ts +62 -0
  129. package/dist/db/firestore-document.d.ts.map +1 -0
  130. package/dist/db/firestore-document.js +238 -0
  131. package/dist/db/firestore-document.js.map +1 -0
  132. package/dist/db/firestore-endpoints.d.ts +41 -0
  133. package/dist/db/firestore-endpoints.d.ts.map +1 -0
  134. package/dist/db/firestore-endpoints.js +735 -0
  135. package/dist/db/firestore-endpoints.js.map +1 -0
  136. package/dist/db/firestore-error-codes.d.ts +24 -0
  137. package/dist/db/firestore-error-codes.d.ts.map +1 -0
  138. package/dist/db/firestore-error-codes.js +24 -0
  139. package/dist/db/firestore-error-codes.js.map +1 -0
  140. package/dist/db/firestore-logging.d.ts +23 -0
  141. package/dist/db/firestore-logging.d.ts.map +1 -0
  142. package/dist/db/firestore-logging.js +41 -0
  143. package/dist/db/firestore-logging.js.map +1 -0
  144. package/dist/db/firestore-path.d.ts +4 -0
  145. package/dist/db/firestore-path.d.ts.map +1 -0
  146. package/dist/db/firestore-path.js +37 -0
  147. package/dist/db/firestore-path.js.map +1 -0
  148. package/dist/db/firestore-results.d.ts +12 -0
  149. package/dist/db/firestore-results.d.ts.map +1 -0
  150. package/dist/db/firestore-results.js +19 -0
  151. package/dist/db/firestore-results.js.map +1 -0
  152. package/dist/db/firestore-settings.d.ts +22 -0
  153. package/dist/db/firestore-settings.d.ts.map +1 -0
  154. package/dist/db/firestore-settings.js +83 -0
  155. package/dist/db/firestore-settings.js.map +1 -0
  156. package/dist/db/firestore-telemetry.d.ts +21 -0
  157. package/dist/db/firestore-telemetry.d.ts.map +1 -0
  158. package/dist/db/firestore-telemetry.js +84 -0
  159. package/dist/db/firestore-telemetry.js.map +1 -0
  160. package/dist/db/firestore-types.d.ts +25 -0
  161. package/dist/db/firestore-types.d.ts.map +1 -0
  162. package/dist/db/firestore-types.js +2 -0
  163. package/dist/db/firestore-types.js.map +1 -0
  164. package/dist/db/firestore.d.ts +151 -0
  165. package/dist/db/firestore.d.ts.map +1 -0
  166. package/dist/db/firestore.js +505 -0
  167. package/dist/db/firestore.js.map +1 -0
  168. package/dist/db/geo-point.d.ts +11 -0
  169. package/dist/db/geo-point.d.ts.map +1 -0
  170. package/dist/db/geo-point.js +29 -0
  171. package/dist/db/geo-point.js.map +1 -0
  172. package/dist/db/json-stream.d.ts +3 -0
  173. package/dist/db/json-stream.d.ts.map +1 -0
  174. package/dist/db/json-stream.js +117 -0
  175. package/dist/db/json-stream.js.map +1 -0
  176. package/dist/db/pipeline-expression.d.ts +293 -0
  177. package/dist/db/pipeline-expression.d.ts.map +1 -0
  178. package/dist/db/pipeline-expression.js +1436 -0
  179. package/dist/db/pipeline-expression.js.map +1 -0
  180. package/dist/db/pipeline-query.d.ts +6 -0
  181. package/dist/db/pipeline-query.d.ts.map +1 -0
  182. package/dist/db/pipeline-query.js +91 -0
  183. package/dist/db/pipeline-query.js.map +1 -0
  184. package/dist/db/pipeline.d.ts +120 -0
  185. package/dist/db/pipeline.d.ts.map +1 -0
  186. package/dist/db/pipeline.js +396 -0
  187. package/dist/db/pipeline.js.map +1 -0
  188. package/dist/db/query-document-snapshot.d.ts +2 -0
  189. package/dist/db/query-document-snapshot.d.ts.map +1 -0
  190. package/dist/db/query-document-snapshot.js +2 -0
  191. package/dist/db/query-document-snapshot.js.map +1 -0
  192. package/dist/db/query-partition.d.ts +14 -0
  193. package/dist/db/query-partition.d.ts.map +1 -0
  194. package/dist/db/query-partition.js +32 -0
  195. package/dist/db/query-partition.js.map +1 -0
  196. package/dist/db/query-request.d.ts +96 -0
  197. package/dist/db/query-request.d.ts.map +1 -0
  198. package/dist/db/query-request.js +283 -0
  199. package/dist/db/query-request.js.map +1 -0
  200. package/dist/db/query.d.ts +129 -0
  201. package/dist/db/query.d.ts.map +1 -0
  202. package/dist/db/query.js +468 -0
  203. package/dist/db/query.js.map +1 -0
  204. package/dist/db/recursive-delete.d.ts +6 -0
  205. package/dist/db/recursive-delete.d.ts.map +1 -0
  206. package/dist/db/recursive-delete.js +38 -0
  207. package/dist/db/recursive-delete.js.map +1 -0
  208. package/dist/db/snapshot-listener.d.ts +10 -0
  209. package/dist/db/snapshot-listener.d.ts.map +1 -0
  210. package/dist/db/snapshot-listener.js +71 -0
  211. package/dist/db/snapshot-listener.js.map +1 -0
  212. package/dist/db/timestamp.d.ts +29 -0
  213. package/dist/db/timestamp.d.ts.map +1 -0
  214. package/dist/db/timestamp.js +98 -0
  215. package/dist/db/timestamp.js.map +1 -0
  216. package/dist/db/transaction.d.ts +44 -0
  217. package/dist/db/transaction.d.ts.map +1 -0
  218. package/dist/db/transaction.js +177 -0
  219. package/dist/db/transaction.js.map +1 -0
  220. package/dist/db/value-equality.d.ts +3 -0
  221. package/dist/db/value-equality.d.ts.map +1 -0
  222. package/dist/db/value-equality.js +29 -0
  223. package/dist/db/value-equality.js.map +1 -0
  224. package/dist/db/vector-query.d.ts +38 -0
  225. package/dist/db/vector-query.d.ts.map +1 -0
  226. package/dist/db/vector-query.js +110 -0
  227. package/dist/db/vector-query.js.map +1 -0
  228. package/dist/db/vector-value.d.ts +8 -0
  229. package/dist/db/vector-value.d.ts.map +1 -0
  230. package/dist/db/vector-value.js +25 -0
  231. package/dist/db/vector-value.js.map +1 -0
  232. package/dist/db/write-batch.d.ts +25 -0
  233. package/dist/db/write-batch.d.ts.map +1 -0
  234. package/dist/db/write-batch.js +72 -0
  235. package/dist/db/write-batch.js.map +1 -0
  236. package/dist/db/write-request.d.ts +36 -0
  237. package/dist/db/write-request.d.ts.map +1 -0
  238. package/dist/db/write-request.js +257 -0
  239. package/dist/db/write-request.js.map +1 -0
  240. package/dist/firebase-edge-server.d.ts +143 -36
  241. package/dist/firebase-edge-server.d.ts.map +1 -1
  242. package/dist/firebase-edge-server.js +463 -258
  243. package/dist/firebase-edge-server.js.map +1 -1
  244. package/dist/index.d.ts +6 -0
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js +5 -0
  247. package/dist/index.js.map +1 -1
  248. package/dist/rest-fetch.d.ts +1 -1
  249. package/dist/rest-fetch.d.ts.map +1 -1
  250. package/dist/storage/storage-acl.d.ts +48 -0
  251. package/dist/storage/storage-acl.d.ts.map +1 -0
  252. package/dist/storage/storage-acl.js +101 -0
  253. package/dist/storage/storage-acl.js.map +1 -0
  254. package/dist/storage/storage-bucket-endpoints.d.ts +10 -0
  255. package/dist/storage/storage-bucket-endpoints.d.ts.map +1 -0
  256. package/dist/storage/storage-bucket-endpoints.js +514 -0
  257. package/dist/storage/storage-bucket-endpoints.js.map +1 -0
  258. package/dist/storage/storage-bucket-types.d.ts +183 -0
  259. package/dist/storage/storage-bucket-types.d.ts.map +1 -0
  260. package/dist/storage/storage-bucket-types.js +2 -0
  261. package/dist/storage/storage-bucket-types.js.map +1 -0
  262. package/dist/storage/storage-bucket.d.ts +122 -0
  263. package/dist/storage/storage-bucket.d.ts.map +1 -0
  264. package/dist/storage/storage-bucket.js +544 -0
  265. package/dist/storage/storage-bucket.js.map +1 -0
  266. package/dist/storage/storage-channel.d.ts +10 -0
  267. package/dist/storage/storage-channel.d.ts.map +1 -0
  268. package/dist/storage/storage-channel.js +15 -0
  269. package/dist/storage/storage-channel.js.map +1 -0
  270. package/dist/storage/storage-checksum.d.ts +35 -0
  271. package/dist/storage/storage-checksum.d.ts.map +1 -0
  272. package/dist/storage/storage-checksum.js +312 -0
  273. package/dist/storage/storage-checksum.js.map +1 -0
  274. package/dist/storage/storage-endpoints.d.ts +14 -0
  275. package/dist/storage/storage-endpoints.d.ts.map +1 -0
  276. package/dist/storage/storage-endpoints.js +721 -0
  277. package/dist/storage/storage-endpoints.js.map +1 -0
  278. package/dist/storage/storage-file.d.ts +126 -0
  279. package/dist/storage/storage-file.d.ts.map +1 -0
  280. package/dist/storage/storage-file.js +604 -0
  281. package/dist/storage/storage-file.js.map +1 -0
  282. package/dist/storage/storage-hmac-key.d.ts +26 -0
  283. package/dist/storage/storage-hmac-key.d.ts.map +1 -0
  284. package/dist/storage/storage-hmac-key.js +45 -0
  285. package/dist/storage/storage-hmac-key.js.map +1 -0
  286. package/dist/storage/storage-iam.d.ts +20 -0
  287. package/dist/storage/storage-iam.d.ts.map +1 -0
  288. package/dist/storage/storage-iam.js +43 -0
  289. package/dist/storage/storage-iam.js.map +1 -0
  290. package/dist/storage/storage-md5.d.ts +11 -0
  291. package/dist/storage/storage-md5.d.ts.map +1 -0
  292. package/dist/storage/storage-md5.js +96 -0
  293. package/dist/storage/storage-md5.js.map +1 -0
  294. package/dist/storage/storage-notification.d.ts +24 -0
  295. package/dist/storage/storage-notification.d.ts.map +1 -0
  296. package/dist/storage/storage-notification.js +40 -0
  297. package/dist/storage/storage-notification.js.map +1 -0
  298. package/dist/storage/storage-progress.d.ts +4 -0
  299. package/dist/storage/storage-progress.d.ts.map +1 -0
  300. package/dist/storage/storage-progress.js +17 -0
  301. package/dist/storage/storage-progress.js.map +1 -0
  302. package/dist/storage/storage-reference-endpoints.d.ts +63 -0
  303. package/dist/storage/storage-reference-endpoints.d.ts.map +1 -0
  304. package/dist/storage/storage-reference-endpoints.js +276 -0
  305. package/dist/storage/storage-reference-endpoints.js.map +1 -0
  306. package/dist/storage/storage-reference-helpers.d.ts +12 -0
  307. package/dist/storage/storage-reference-helpers.d.ts.map +1 -0
  308. package/dist/storage/storage-reference-helpers.js +72 -0
  309. package/dist/storage/storage-reference-helpers.js.map +1 -0
  310. package/dist/storage/storage-reference-signing.d.ts +40 -0
  311. package/dist/storage/storage-reference-signing.d.ts.map +1 -0
  312. package/dist/storage/storage-reference-signing.js +289 -0
  313. package/dist/storage/storage-reference-signing.js.map +1 -0
  314. package/dist/storage/storage-reference-types.d.ts +76 -0
  315. package/dist/storage/storage-reference-types.d.ts.map +1 -0
  316. package/dist/storage/storage-reference-types.js +2 -0
  317. package/dist/storage/storage-reference-types.js.map +1 -0
  318. package/dist/storage/storage-results.d.ts +8 -0
  319. package/dist/storage/storage-results.d.ts.map +1 -0
  320. package/dist/storage/storage-results.js +32 -0
  321. package/dist/storage/storage-results.js.map +1 -0
  322. package/dist/storage/storage-resumable.d.ts +18 -0
  323. package/dist/storage/storage-resumable.d.ts.map +1 -0
  324. package/dist/storage/storage-resumable.js +166 -0
  325. package/dist/storage/storage-resumable.js.map +1 -0
  326. package/dist/storage/storage-retry.d.ts +9 -0
  327. package/dist/storage/storage-retry.d.ts.map +1 -0
  328. package/dist/storage/storage-retry.js +104 -0
  329. package/dist/storage/storage-retry.js.map +1 -0
  330. package/dist/storage/storage-signed-url.d.ts +9 -0
  331. package/dist/storage/storage-signed-url.d.ts.map +1 -0
  332. package/dist/storage/storage-signed-url.js +96 -0
  333. package/dist/storage/storage-signed-url.js.map +1 -0
  334. package/dist/storage/storage-special-endpoints.d.ts +10 -0
  335. package/dist/storage/storage-special-endpoints.d.ts.map +1 -0
  336. package/dist/storage/storage-special-endpoints.js +394 -0
  337. package/dist/storage/storage-special-endpoints.js.map +1 -0
  338. package/dist/storage/storage-special-types.d.ts +154 -0
  339. package/dist/storage/storage-special-types.d.ts.map +1 -0
  340. package/dist/storage/storage-special-types.js +2 -0
  341. package/dist/storage/storage-special-types.js.map +1 -0
  342. package/dist/storage/storage-types.d.ts +251 -0
  343. package/dist/storage/storage-types.d.ts.map +1 -0
  344. package/dist/storage/storage-types.js +2 -0
  345. package/dist/storage/storage-types.js.map +1 -0
  346. package/dist/storage/storage-upload-stream.d.ts +41 -0
  347. package/dist/storage/storage-upload-stream.d.ts.map +1 -0
  348. package/dist/storage/storage-upload-stream.js +335 -0
  349. package/dist/storage/storage-upload-stream.js.map +1 -0
  350. package/dist/storage/storage-xml-signing.d.ts +17 -0
  351. package/dist/storage/storage-xml-signing.d.ts.map +1 -0
  352. package/dist/storage/storage-xml-signing.js +144 -0
  353. package/dist/storage/storage-xml-signing.js.map +1 -0
  354. package/dist/storage/storage.d.ts +152 -0
  355. package/dist/storage/storage.d.ts.map +1 -0
  356. package/dist/storage/storage.js +532 -0
  357. package/dist/storage/storage.js.map +1 -0
  358. package/dist/utils/token-cache.d.ts.map +1 -1
  359. package/dist/utils/token-cache.js +3 -2
  360. package/dist/utils/token-cache.js.map +1 -1
  361. package/package.json +22 -6
  362. package/dist/auth/auth-endpoint-errors.test.d.ts +0 -2
  363. package/dist/auth/auth-endpoint-errors.test.d.ts.map +0 -1
  364. package/dist/auth/auth-endpoint-errors.test.js +0 -411
  365. package/dist/auth/auth-endpoint-errors.test.js.map +0 -1
  366. package/dist/auth/email-action-request.test.d.ts +0 -2
  367. package/dist/auth/email-action-request.test.d.ts.map +0 -1
  368. package/dist/auth/email-action-request.test.js +0 -128
  369. package/dist/auth/email-action-request.test.js.map +0 -1
  370. package/dist/auth/errors.test.d.ts +0 -2
  371. package/dist/auth/errors.test.d.ts.map +0 -1
  372. package/dist/auth/errors.test.js +0 -123
  373. package/dist/auth/errors.test.js.map +0 -1
  374. package/dist/auth/firebase-admin-auth.test.d.ts +0 -2
  375. package/dist/auth/firebase-admin-auth.test.d.ts.map +0 -1
  376. package/dist/auth/firebase-admin-auth.test.js +0 -1542
  377. package/dist/auth/firebase-admin-auth.test.js.map +0 -1
  378. package/dist/auth/firebase-auth-endpoints.test.d.ts +0 -2
  379. package/dist/auth/firebase-auth-endpoints.test.d.ts.map +0 -1
  380. package/dist/auth/firebase-auth-endpoints.test.js +0 -1082
  381. package/dist/auth/firebase-auth-endpoints.test.js.map +0 -1
  382. package/dist/auth/firebase-auth.test.d.ts +0 -2
  383. package/dist/auth/firebase-auth.test.d.ts.map +0 -1
  384. package/dist/auth/firebase-auth.test.js +0 -167
  385. package/dist/auth/firebase-auth.test.js.map +0 -1
  386. package/dist/auth/firebase-jwt.test.d.ts +0 -2
  387. package/dist/auth/firebase-jwt.test.d.ts.map +0 -1
  388. package/dist/auth/firebase-jwt.test.js +0 -164
  389. package/dist/auth/firebase-jwt.test.js.map +0 -1
  390. package/dist/auth/github-oauth.d.ts +0 -19
  391. package/dist/auth/github-oauth.d.ts.map +0 -1
  392. package/dist/auth/github-oauth.js +0 -145
  393. package/dist/auth/github-oauth.js.map +0 -1
  394. package/dist/auth/github-oauth.test.d.ts +0 -2
  395. package/dist/auth/github-oauth.test.d.ts.map +0 -1
  396. package/dist/auth/github-oauth.test.js +0 -202
  397. package/dist/auth/github-oauth.test.js.map +0 -1
  398. package/dist/auth/google-oauth.test.d.ts +0 -2
  399. package/dist/auth/google-oauth.test.d.ts.map +0 -1
  400. package/dist/auth/google-oauth.test.js +0 -200
  401. package/dist/auth/google-oauth.test.js.map +0 -1
  402. package/dist/auth/oauth.d.ts +0 -3
  403. package/dist/auth/oauth.d.ts.map +0 -1
  404. package/dist/auth/oauth.js +0 -48
  405. package/dist/auth/oauth.js.map +0 -1
  406. package/dist/auth/oauth.test.d.ts +0 -2
  407. package/dist/auth/oauth.test.d.ts.map +0 -1
  408. package/dist/auth/oauth.test.js +0 -109
  409. package/dist/auth/oauth.test.js.map +0 -1
  410. package/dist/auth/user-batch.test.d.ts +0 -2
  411. package/dist/auth/user-batch.test.d.ts.map +0 -1
  412. package/dist/auth/user-batch.test.js +0 -73
  413. package/dist/auth/user-batch.test.js.map +0 -1
  414. package/dist/auth/user-import.test.d.ts +0 -2
  415. package/dist/auth/user-import.test.d.ts.map +0 -1
  416. package/dist/auth/user-import.test.js +0 -217
  417. package/dist/auth/user-import.test.js.map +0 -1
  418. package/dist/auth/user-record.test.d.ts +0 -2
  419. package/dist/auth/user-record.test.d.ts.map +0 -1
  420. package/dist/auth/user-record.test.js +0 -198
  421. package/dist/auth/user-record.test.js.map +0 -1
  422. package/dist/auth/user-request.test.d.ts +0 -2
  423. package/dist/auth/user-request.test.d.ts.map +0 -1
  424. package/dist/auth/user-request.test.js +0 -327
  425. package/dist/auth/user-request.test.js.map +0 -1
  426. package/dist/firebase-edge-errors.test.d.ts +0 -2
  427. package/dist/firebase-edge-errors.test.d.ts.map +0 -1
  428. package/dist/firebase-edge-errors.test.js +0 -72
  429. package/dist/firebase-edge-errors.test.js.map +0 -1
  430. package/dist/firebase-edge-server.test.d.ts +0 -2
  431. package/dist/firebase-edge-server.test.d.ts.map +0 -1
  432. package/dist/firebase-edge-server.test.js +0 -293
  433. package/dist/firebase-edge-server.test.js.map +0 -1
  434. package/dist/rest-fetch.test.d.ts +0 -2
  435. package/dist/rest-fetch.test.d.ts.map +0 -1
  436. package/dist/rest-fetch.test.js +0 -164
  437. package/dist/rest-fetch.test.js.map +0 -1
@@ -1,1542 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { FirebaseAdminAuth } from './firebase-admin-auth.js';
3
- import { generateEmailActionLink, deleteAccountsAdmin, importAccountsAdmin, getAccountsInfo, createAccountAdmin, updateAccountAdmin, deleteAccountAdmin, downloadAccount, getAccountInfo, createSessionCookie as createSessionCookieEndpoint } from './firebase-auth-endpoints.js';
4
- import { getToken } from './google-oauth.js';
5
- import { signJWTCustomToken, verifyJWT, verifySessionJWT } from './firebase-jwt.js';
6
- import { FirebaseEdgeError, FirebaseAdminAuthErrorInfo, FirebaseEndpointErrorInfo, JWTErrorInfo } from './errors.js';
7
- vi.mock('./firebase-auth-endpoints.js', () => ({
8
- generateEmailActionLink: vi.fn(),
9
- deleteAccountsAdmin: vi.fn(),
10
- importAccountsAdmin: vi.fn(),
11
- getAccountsInfo: vi.fn(),
12
- createAccountAdmin: vi.fn(),
13
- updateAccountAdmin: vi.fn(),
14
- deleteAccountAdmin: vi.fn(),
15
- downloadAccount: vi.fn(),
16
- getAccountInfo: vi.fn(),
17
- createSessionCookie: vi.fn()
18
- }));
19
- vi.mock('./firebase-jwt.js', () => ({
20
- signJWTCustomToken: vi.fn(),
21
- verifyJWT: vi.fn(),
22
- verifySessionJWT: vi.fn()
23
- }));
24
- vi.mock('./google-oauth.js', () => ({
25
- getToken: vi.fn()
26
- }));
27
- const mockedGetToken = vi.mocked(getToken);
28
- const mockedGetAccountInfo = vi.mocked(getAccountInfo);
29
- const mockedCreateSessionCookieEndpoint = vi.mocked(createSessionCookieEndpoint);
30
- const mockedVerifyJWT = vi.mocked(verifyJWT);
31
- const mockedVerifySessionJWT = vi.mocked(verifySessionJWT);
32
- const mockedSignJWTCustomToken = vi.mocked(signJWTCustomToken);
33
- const serviceAccountKey = {
34
- type: 'service_account',
35
- project_id: 'test-project',
36
- private_key_id: 'test-private-key-id',
37
- private_key: 'test-private-key',
38
- client_email: 'test@test-project.iam.gserviceaccount.com',
39
- client_id: 'test-client-id',
40
- auth_uri: 'https://accounts.google.com/o/oauth2/auth',
41
- token_uri: 'https://oauth2.googleapis.com/token',
42
- auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
43
- client_x509_cert_url: 'https://www.googleapis.com/robot/v1/metadata/x509/test%40test-project.iam.gserviceaccount.com'
44
- };
45
- // Proper mock data that matches the expected types
46
- const mockGoogleTokenResponse = {
47
- access_token: 'test-access-token',
48
- expires_in: 3600,
49
- scope: 'scope',
50
- token_type: 'Bearer',
51
- id_token: 'test-id-token'
52
- };
53
- const mockUserRecord = {
54
- localId: 'uid-1',
55
- email: 'test@example.com',
56
- emailVerified: true,
57
- disabled: false
58
- };
59
- const mockFirebasePayload = {
60
- iss: 'https://securetoken.google.com/test-project',
61
- aud: 'test-project',
62
- auth_time: 1000,
63
- user_id: 'uid-1',
64
- sub: 'uid-1',
65
- iat: 1000,
66
- exp: 2000,
67
- email: 'test@example.com',
68
- email_verified: true,
69
- firebase: {
70
- identities: {
71
- email: ['test@example.com']
72
- },
73
- sign_in_provider: 'password'
74
- }
75
- };
76
- describe('FirebaseAdminAuth', () => {
77
- let auth;
78
- let authWithTenant;
79
- beforeEach(() => {
80
- auth = new FirebaseAdminAuth(serviceAccountKey);
81
- authWithTenant = new FirebaseAdminAuth(serviceAccountKey, 'test-tenant-id');
82
- vi.clearAllMocks();
83
- });
84
- afterEach(() => {
85
- vi.resetAllMocks();
86
- });
87
- describe('getUserByProviderUid', () => {
88
- it.each([
89
- [
90
- 'google.com',
91
- 'google-123',
92
- {
93
- federatedUserId: [
94
- { providerId: 'google.com', rawId: 'google-123' }
95
- ]
96
- }
97
- ],
98
- ['email', 'test@example.com', { email: ['test@example.com'] }],
99
- ['phone', '+15551234567', { phoneNumber: ['+15551234567'] }]
100
- ])('looks up %s using the existing batch helper', async (providerId, uid, request) => {
101
- const fetchFn = vi.fn();
102
- const admin = new FirebaseAdminAuth(serviceAccountKey, 'tenant', fetchFn);
103
- mockedGetToken.mockResolvedValue({
104
- data: mockGoogleTokenResponse,
105
- error: null
106
- });
107
- vi.mocked(getAccountsInfo).mockResolvedValue({
108
- data: {
109
- users: [
110
- {
111
- ...mockUserRecord,
112
- phoneNumber: '+15551234567',
113
- providerUserInfo: [
114
- {
115
- providerId: 'google.com',
116
- rawId: 'google-123'
117
- }
118
- ]
119
- }
120
- ]
121
- },
122
- error: null
123
- });
124
- const result = await admin.getUserByProviderUid(providerId, uid);
125
- expect(result.error).toBeNull();
126
- expect(result.data?.uid).toBe('uid-1');
127
- expect(result.data?.toJSON()).toMatchObject({ uid: 'uid-1' });
128
- expect(getAccountsInfo).toHaveBeenCalledWith(request, 'test-access-token', 'test-project', 'tenant', fetchFn);
129
- });
130
- it('returns user-not-found for an unmatched provider UID', async () => {
131
- vi.spyOn(auth, 'getUsers').mockResolvedValue({
132
- data: {
133
- users: [],
134
- notFound: [
135
- { providerId: 'google.com', providerUid: 'missing' }
136
- ]
137
- },
138
- error: null
139
- });
140
- expect((await auth.getUserByProviderUid('google.com', 'missing')).error
141
- ?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_USER_NOT_FOUND.code);
142
- });
143
- it.each([
144
- ['', 'uid'],
145
- ['google.com', ''],
146
- [null, 'uid'],
147
- ['google.com', null],
148
- ['email', 'invalid'],
149
- ['phone', 'invalid']
150
- ])('rejects invalid identifiers %s/%s before authentication', async (providerId, uid) => {
151
- expect((await auth.getUserByProviderUid(providerId, uid)).error).toBeInstanceOf(FirebaseEdgeError);
152
- expect(mockedGetToken).not.toHaveBeenCalled();
153
- });
154
- it('preserves lookup failures', async () => {
155
- const error = new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_USER_LOOKUP_FAILED);
156
- vi.spyOn(auth, 'getUsers').mockResolvedValue({ data: null, error });
157
- expect(await auth.getUserByProviderUid('google.com', 'uid')).toEqual({ data: null, error });
158
- });
159
- });
160
- describe('generateVerifyAndChangeEmailLink', () => {
161
- it.each([undefined, { url: 'https://example.com/account' }])('generates a link with settings %j', async (settings) => {
162
- const fetchFn = vi.fn();
163
- const admin = new FirebaseAdminAuth(serviceAccountKey, 'tenant', fetchFn);
164
- mockedGetToken.mockResolvedValue({
165
- data: mockGoogleTokenResponse,
166
- error: null
167
- });
168
- vi.mocked(generateEmailActionLink).mockResolvedValue({
169
- data: 'https://example.com/action',
170
- error: null
171
- });
172
- expect(await admin.generateVerifyAndChangeEmailLink('old@example.com', 'new@example.com', settings)).toEqual({ data: 'https://example.com/action', error: null });
173
- expect(generateEmailActionLink).toHaveBeenCalledWith('test-project', {
174
- requestType: 'VERIFY_AND_CHANGE_EMAIL',
175
- email: 'old@example.com',
176
- newEmail: 'new@example.com',
177
- returnOobLink: true,
178
- ...(settings
179
- ? {
180
- continueUrl: settings.url,
181
- canHandleCodeInApp: false
182
- }
183
- : {})
184
- }, 'test-access-token', fetchFn, 'tenant');
185
- });
186
- it.each([
187
- ['invalid', 'new@example.com'],
188
- ['old@example.com', 'invalid'],
189
- ['old@example.com', undefined]
190
- ])('rejects invalid addresses %s/%s', async (email, newEmail) => {
191
- const result = await auth.generateVerifyAndChangeEmailLink(email, newEmail);
192
- expect(result.error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_API_INVALID_ARGUMENT.code);
193
- expect(mockedGetToken).not.toHaveBeenCalled();
194
- });
195
- it('returns credential errors without requesting a link', async () => {
196
- mockedGetToken.mockResolvedValue({
197
- data: null,
198
- error: new Error('credentials')
199
- });
200
- expect((await auth.generateVerifyAndChangeEmailLink('old@example.com', 'new@example.com')).error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED
201
- .code);
202
- expect(generateEmailActionLink).not.toHaveBeenCalled();
203
- });
204
- it('wraps endpoint failures with their cause', async () => {
205
- const cause = new Error('email already exists');
206
- mockedGetToken.mockResolvedValue({
207
- data: mockGoogleTokenResponse,
208
- error: null
209
- });
210
- vi.mocked(generateEmailActionLink).mockResolvedValue({
211
- data: null,
212
- error: cause
213
- });
214
- const result = await auth.generateVerifyAndChangeEmailLink('old@example.com', 'new@example.com');
215
- expect(result.error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_EMAIL_ACTION_LINK_FAILED.code);
216
- expect(result.error?.cause).toBe(cause);
217
- });
218
- });
219
- describe('setCustomUserClaims', () => {
220
- beforeEach(() => {
221
- mockedGetToken.mockResolvedValue({
222
- data: mockGoogleTokenResponse,
223
- error: null
224
- });
225
- vi.mocked(updateAccountAdmin).mockResolvedValue({
226
- data: { localId: 'uid' },
227
- error: null
228
- });
229
- });
230
- it('uses the existing update helper with tenant and custom fetch', async () => {
231
- const customFetch = vi.fn();
232
- const instance = new FirebaseAdminAuth(serviceAccountKey, 'tenant', customFetch);
233
- expect(await instance.setCustomUserClaims('uid', { role: 'editor' })).toEqual({ data: undefined, error: null });
234
- expect(updateAccountAdmin).toHaveBeenCalledExactlyOnceWith('test-project', 'uid', { customAttributes: '{"role":"editor"}' }, 'test-access-token', customFetch, 'tenant');
235
- expect(getAccountInfo).not.toHaveBeenCalled();
236
- });
237
- it('clears claims with null', async () => {
238
- expect((await auth.setCustomUserClaims('uid', null)).error).toBeNull();
239
- expect(updateAccountAdmin).toHaveBeenCalledWith('test-project', 'uid', { customAttributes: '{}' }, 'test-access-token', undefined, undefined);
240
- });
241
- it('validates UID and claims before authentication', async () => {
242
- expect((await auth.setCustomUserClaims('', {})).error).not.toBeNull();
243
- expect((await auth.setCustomUserClaims('a'.repeat(129), {})).error).not.toBeNull();
244
- expect((await auth.setCustomUserClaims('uid', { sub: 'reserved' }))
245
- .error).not.toBeNull();
246
- expect(mockedGetToken).not.toHaveBeenCalled();
247
- expect(updateAccountAdmin).not.toHaveBeenCalled();
248
- });
249
- it('uses cached credentials', async () => {
250
- const cache = {
251
- getCache: vi.fn().mockResolvedValue(mockGoogleTokenResponse),
252
- setCache: vi.fn()
253
- };
254
- const instance = new FirebaseAdminAuth(serviceAccountKey, undefined, undefined, cache);
255
- expect((await instance.setCustomUserClaims('uid', {})).error).toBeNull();
256
- expect(mockedGetToken).not.toHaveBeenCalled();
257
- });
258
- it('returns credential failures without updating', async () => {
259
- const error = new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED);
260
- mockedGetToken.mockResolvedValue({ data: null, error });
261
- expect(await auth.setCustomUserClaims('uid', {})).toEqual({
262
- data: null,
263
- error
264
- });
265
- expect(updateAccountAdmin).not.toHaveBeenCalled();
266
- });
267
- it('guards against missing access tokens', async () => {
268
- mockedGetToken.mockResolvedValue({
269
- data: {},
270
- error: null
271
- });
272
- expect((await auth.setCustomUserClaims('uid', {})).error?.code).toBe('auth/admin-no-token-returned');
273
- expect(updateAccountAdmin).not.toHaveBeenCalled();
274
- });
275
- it('preserves endpoint errors including user-not-found', async () => {
276
- const cause = new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_USER_NOT_FOUND);
277
- vi.mocked(updateAccountAdmin).mockResolvedValue({
278
- data: null,
279
- error: cause
280
- });
281
- const result = await auth.setCustomUserClaims('missing', {});
282
- expect(result.data).toBeNull();
283
- expect(result.error?.code).toBe('auth/admin-set-custom-claims-failed');
284
- expect(result.error?.cause).toBe(cause);
285
- });
286
- it('rejects missing confirmation data', async () => {
287
- vi.mocked(updateAccountAdmin).mockResolvedValue({
288
- data: { localId: '' },
289
- error: null
290
- });
291
- expect((await auth.setCustomUserClaims('uid', {})).error?.code).toBe('auth/admin-set-custom-claims-failed');
292
- });
293
- it('returns network and credential exceptions instead of rejecting', async () => {
294
- const cause = new Error('offline');
295
- vi.mocked(updateAccountAdmin).mockRejectedValue(cause);
296
- expect((await auth.setCustomUserClaims('uid', {})).error?.cause).toBe(cause);
297
- mockedGetToken.mockRejectedValue('token failure');
298
- expect((await auth.setCustomUserClaims('uid', {})).error?.cause).toBeInstanceOf(Error);
299
- });
300
- });
301
- describe('phone lookup and bulk user management', () => {
302
- beforeEach(() => {
303
- mockedGetToken.mockResolvedValue({
304
- data: mockGoogleTokenResponse,
305
- error: null
306
- });
307
- mockedGetAccountInfo.mockResolvedValue({
308
- data: mockUserRecord,
309
- error: null
310
- });
311
- vi.mocked(deleteAccountsAdmin).mockResolvedValue({
312
- data: {},
313
- error: null
314
- });
315
- vi.mocked(importAccountsAdmin).mockResolvedValue({
316
- data: {},
317
- error: null
318
- });
319
- });
320
- it('looks up a phone number and returns a converted user record', async () => {
321
- const customFetch = vi.fn();
322
- const instance = new FirebaseAdminAuth(serviceAccountKey, 'tenant', customFetch);
323
- const result = await instance.getUserByPhoneNumber('+15555550100');
324
- expect(result.error).toBeNull();
325
- expect(result.data?.uid).toBe('uid-1');
326
- expect(result.data?.toJSON()).toMatchObject({ uid: 'uid-1' });
327
- expect(getAccountInfo).toHaveBeenCalledWith({ phoneNumber: '+15555550100' }, 'test-access-token', 'test-project', 'tenant', customFetch);
328
- });
329
- it('returns user-not-found when no phone match exists', async () => {
330
- mockedGetAccountInfo.mockResolvedValue({ data: null, error: null });
331
- expect((await auth.getUserByPhoneNumber('+15555550100')).error?.code).toBe('auth/admin-user-not-found');
332
- });
333
- it.each(['', '555', null, 1])('rejects invalid phone number %s before authentication', async (phone) => {
334
- expect((await auth.getUserByPhoneNumber(phone)).error).toBeInstanceOf(FirebaseEdgeError);
335
- expect(mockedGetToken).not.toHaveBeenCalled();
336
- });
337
- it('deletes a batch with tenant, custom fetch, counts, and indexed errors', async () => {
338
- const customFetch = vi.fn();
339
- const instance = new FirebaseAdminAuth(serviceAccountKey, 'tenant', customFetch);
340
- vi.mocked(deleteAccountsAdmin).mockResolvedValue({
341
- data: { errors: [{ index: 1, message: 'failure' }] },
342
- error: null
343
- });
344
- const result = await instance.deleteUsers([
345
- 'one',
346
- 'two',
347
- 'missing'
348
- ]);
349
- expect(result.error).toBeNull();
350
- expect(result.data).toMatchObject({
351
- successCount: 2,
352
- failureCount: 1,
353
- errors: [{ index: 1, error: { message: 'failure' } }]
354
- });
355
- expect(deleteAccountsAdmin).toHaveBeenCalledWith('test-project', ['one', 'two', 'missing'], 'test-access-token', customFetch, 'tenant');
356
- });
357
- it('returns empty delete and import results without network requests', async () => {
358
- const result = {
359
- data: { successCount: 0, failureCount: 0, errors: [] },
360
- error: null
361
- };
362
- expect(await auth.deleteUsers([])).toEqual(result);
363
- expect(await auth.importUsers([])).toEqual(result);
364
- expect(mockedGetToken).not.toHaveBeenCalled();
365
- });
366
- it('rejects invalid delete batches and oversized imports before authentication', async () => {
367
- expect((await auth.deleteUsers(['one', ''])).error).not.toBeNull();
368
- expect((await auth.deleteUsers(Array(1001).fill('uid'))).error).not.toBeNull();
369
- expect((await auth.importUsers(Array(1001).fill({ uid: 'uid' }))).error).not.toBeNull();
370
- expect(mockedGetToken).not.toHaveBeenCalled();
371
- });
372
- it('merges local and server import failures using original indices', async () => {
373
- const customFetch = vi.fn();
374
- const instance = new FirebaseAdminAuth(serviceAccountKey, 'tenant', customFetch);
375
- vi.mocked(importAccountsAdmin).mockResolvedValue({
376
- data: { error: [{ index: 1, message: 'DUPLICATE_LOCAL_ID' }] },
377
- error: null
378
- });
379
- const result = await instance.importUsers([
380
- { uid: '' },
381
- { uid: 'one' },
382
- { uid: 'two' }
383
- ]);
384
- expect(result.error).toBeNull();
385
- expect(result.data).toMatchObject({
386
- successCount: 1,
387
- failureCount: 2,
388
- errors: [{ index: 0 }, { index: 2 }]
389
- });
390
- expect(importAccountsAdmin).toHaveBeenCalledWith('test-project', { users: [{ localId: 'one' }, { localId: 'two' }] }, 'test-access-token', customFetch, 'tenant');
391
- });
392
- it('returns all-invalid imports locally and rejects missing password settings', async () => {
393
- expect(await auth.importUsers([{ uid: '' }])).toMatchObject({
394
- data: { successCount: 0, failureCount: 1 },
395
- error: null
396
- });
397
- expect((await auth.importUsers([
398
- { uid: 'uid', passwordHash: new Uint8Array([1]) }
399
- ])).error).not.toBeNull();
400
- expect(mockedGetToken).not.toHaveBeenCalled();
401
- expect(importAccountsAdmin).not.toHaveBeenCalled();
402
- });
403
- it('sends the selected hashing configuration with password imports', async () => {
404
- await auth.importUsers([{ uid: 'uid', passwordHash: new Uint8Array([1]) }], { hash: { algorithm: 'BCRYPT' } });
405
- expect(importAccountsAdmin).toHaveBeenCalledWith('test-project', {
406
- users: [{ localId: 'uid', passwordHash: 'AQ==' }],
407
- hashAlgorithm: 'BCRYPT'
408
- }, 'test-access-token', undefined, undefined);
409
- });
410
- it('uses cached credentials for all three methods', async () => {
411
- const cache = {
412
- getCache: vi.fn().mockResolvedValue(mockGoogleTokenResponse),
413
- setCache: vi.fn()
414
- };
415
- const instance = new FirebaseAdminAuth(serviceAccountKey, undefined, undefined, cache);
416
- expect((await instance.getUserByPhoneNumber('+15555550100')).error).toBeNull();
417
- expect((await instance.deleteUsers(['uid'])).error).toBeNull();
418
- expect((await instance.importUsers([{ uid: 'uid' }])).error).toBeNull();
419
- expect(mockedGetToken).not.toHaveBeenCalled();
420
- });
421
- const operations = [
422
- {
423
- name: 'phone',
424
- run: () => auth.getUserByPhoneNumber('+15555550100'),
425
- endpoint: vi.mocked(getAccountInfo)
426
- },
427
- {
428
- name: 'delete',
429
- run: () => auth.deleteUsers(['uid']),
430
- endpoint: vi.mocked(deleteAccountsAdmin)
431
- },
432
- {
433
- name: 'import',
434
- run: () => auth.importUsers([{ uid: 'uid' }]),
435
- endpoint: vi.mocked(importAccountsAdmin)
436
- }
437
- ];
438
- describe.each(operations)('$name failures', ({ run, endpoint }) => {
439
- it('propagates token failures without calling the endpoint', async () => {
440
- const error = new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED);
441
- mockedGetToken.mockResolvedValue({ data: null, error });
442
- expect(await run()).toEqual({ data: null, error });
443
- expect(endpoint).not.toHaveBeenCalled();
444
- });
445
- it('guards against a missing access token', async () => {
446
- mockedGetToken.mockResolvedValue({
447
- data: {},
448
- error: null
449
- });
450
- expect((await run()).error?.code).toBe('auth/admin-no-token-returned');
451
- expect(endpoint).not.toHaveBeenCalled();
452
- });
453
- it('returns endpoint errors and network exceptions', async () => {
454
- const error = new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_PERMISSION_DENIED);
455
- endpoint.mockResolvedValue({ data: null, error });
456
- expect(await run()).toMatchObject({
457
- data: null,
458
- error: expect.any(FirebaseEdgeError)
459
- });
460
- endpoint.mockRejectedValue(new Error('offline'));
461
- expect(await run()).toMatchObject({
462
- data: null,
463
- error: expect.any(FirebaseEdgeError)
464
- });
465
- });
466
- });
467
- it('returns errors for corrupt bulk responses instead of misleading counts', async () => {
468
- vi.mocked(deleteAccountsAdmin).mockResolvedValue({
469
- data: { errors: [{ index: 5 }] },
470
- error: null
471
- });
472
- vi.mocked(importAccountsAdmin).mockResolvedValue({
473
- data: { error: [{ index: 5 }] },
474
- error: null
475
- });
476
- expect((await auth.deleteUsers(['uid'])).error).not.toBeNull();
477
- expect((await auth.importUsers([{ uid: 'uid' }])).error).not.toBeNull();
478
- });
479
- });
480
- describe('getUsers', () => {
481
- beforeEach(() => {
482
- mockedGetToken.mockResolvedValue({
483
- data: mockGoogleTokenResponse,
484
- error: null
485
- });
486
- vi.mocked(getAccountsInfo).mockResolvedValue({
487
- data: {},
488
- error: null
489
- });
490
- });
491
- it('returns records and unmatched identifiers using one batch request', async () => {
492
- const customFetch = vi.fn();
493
- const instance = new FirebaseAdminAuth(serviceAccountKey, 'tenant', customFetch);
494
- const ids = [{ uid: 'uid' }, { email: 'missing@example.com' }];
495
- vi.mocked(getAccountsInfo).mockResolvedValue({
496
- data: { users: [{ localId: 'uid' }] },
497
- error: null
498
- });
499
- const { data, error } = await instance.getUsers(ids);
500
- expect(error).toBeNull();
501
- expect(data?.users[0]?.uid).toBe('uid');
502
- expect(data?.notFound).toEqual([ids[1]]);
503
- expect(getAccountsInfo).toHaveBeenCalledExactlyOnceWith({ localId: ['uid'], email: ['missing@example.com'] }, 'test-access-token', 'test-project', 'tenant', customFetch);
504
- });
505
- it('returns an empty batch without authentication or requests', async () => {
506
- expect(await auth.getUsers([])).toEqual({
507
- data: { users: [], notFound: [] },
508
- error: null
509
- });
510
- expect(mockedGetToken).not.toHaveBeenCalled();
511
- expect(getAccountsInfo).not.toHaveBeenCalled();
512
- });
513
- it('rejects invalid inputs before authentication', async () => {
514
- expect((await auth.getUsers([{ uid: '' }])).error).toBeInstanceOf(FirebaseEdgeError);
515
- expect((await auth.getUsers(Array(101).fill({ uid: 'uid' }))).error).toBeInstanceOf(FirebaseEdgeError);
516
- expect(mockedGetToken).not.toHaveBeenCalled();
517
- expect(getAccountsInfo).not.toHaveBeenCalled();
518
- });
519
- it('returns all identifiers in notFound when there are no matches', async () => {
520
- expect(await auth.getUsers([{ uid: 'missing' }])).toEqual({
521
- data: { users: [], notFound: [{ uid: 'missing' }] },
522
- error: null
523
- });
524
- });
525
- it('uses cached credentials', async () => {
526
- const cache = {
527
- getCache: vi.fn().mockResolvedValue(mockGoogleTokenResponse),
528
- setCache: vi.fn()
529
- };
530
- const instance = new FirebaseAdminAuth(serviceAccountKey, undefined, undefined, cache);
531
- expect((await instance.getUsers([{ uid: 'uid' }])).error).toBeNull();
532
- expect(mockedGetToken).not.toHaveBeenCalled();
533
- expect(getAccountsInfo).toHaveBeenCalledTimes(1);
534
- });
535
- it('returns credential failures without a lookup', async () => {
536
- const error = new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED);
537
- mockedGetToken.mockResolvedValue({ data: null, error });
538
- expect(await auth.getUsers([{ uid: 'uid' }])).toEqual({
539
- data: null,
540
- error
541
- });
542
- expect(getAccountsInfo).not.toHaveBeenCalled();
543
- });
544
- it('guards against missing access tokens', async () => {
545
- mockedGetToken.mockResolvedValue({
546
- data: {},
547
- error: null
548
- });
549
- expect((await auth.getUsers([{ uid: 'uid' }])).error?.code).toBe('auth/admin-no-token-returned');
550
- expect(getAccountsInfo).not.toHaveBeenCalled();
551
- });
552
- it('retains mapped endpoint failures as the cause', async () => {
553
- const cause = new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_PERMISSION_DENIED);
554
- vi.mocked(getAccountsInfo).mockResolvedValue({
555
- data: null,
556
- error: cause
557
- });
558
- const result = await auth.getUsers([{ uid: 'uid' }]);
559
- expect(result.data).toBeNull();
560
- expect(result.error?.cause).toBe(cause);
561
- });
562
- it.each([null, 'not JSON', { users: [{}] }, { users: 'invalid' }])('returns structured errors for malformed responses %j', async (data) => {
563
- vi.mocked(getAccountsInfo).mockResolvedValue({
564
- data,
565
- error: null
566
- });
567
- const result = await auth.getUsers([{ uid: 'uid' }]);
568
- expect(result.data).toBeNull();
569
- expect(result.error?.code).toBe('auth/admin-user-lookup-failed');
570
- });
571
- it('returns network and token exceptions rather than rejecting', async () => {
572
- vi.mocked(getAccountsInfo).mockRejectedValue(new Error('offline'));
573
- expect((await auth.getUsers([{ uid: 'uid' }])).error?.cause).toBeInstanceOf(Error);
574
- mockedGetToken.mockRejectedValue('token failure');
575
- expect((await auth.getUsers([{ uid: 'uid' }])).error?.cause).toBeInstanceOf(Error);
576
- });
577
- });
578
- describe('user management', () => {
579
- beforeEach(() => {
580
- mockedGetToken.mockResolvedValue({
581
- data: mockGoogleTokenResponse,
582
- error: null
583
- });
584
- mockedGetAccountInfo.mockResolvedValue({
585
- data: mockUserRecord,
586
- error: null
587
- });
588
- vi.mocked(createAccountAdmin).mockResolvedValue({
589
- data: { localId: 'uid-1' },
590
- error: null
591
- });
592
- vi.mocked(updateAccountAdmin).mockResolvedValue({
593
- data: { localId: 'uid-1' },
594
- error: null
595
- });
596
- vi.mocked(deleteAccountAdmin).mockResolvedValue({ error: null });
597
- });
598
- it('creates a user and reads the full record with the same credentials', async () => {
599
- const customFetch = vi.fn();
600
- const instance = new FirebaseAdminAuth(serviceAccountKey, 'tenant', customFetch);
601
- const result = await instance.createUser({
602
- email: 'test@example.com',
603
- photoURL: 'https://example.com/photo',
604
- disabled: false
605
- });
606
- expect(result.error).toBeNull();
607
- expect(result.data?.uid).toBe('uid-1');
608
- expect(result.data?.toJSON()).toMatchObject({
609
- uid: 'uid-1',
610
- email: 'test@example.com'
611
- });
612
- expect(createAccountAdmin).toHaveBeenCalledWith('test-project', {
613
- email: 'test@example.com',
614
- photoUrl: 'https://example.com/photo',
615
- disabled: false
616
- }, 'test-access-token', customFetch, 'tenant');
617
- expect(mockedGetAccountInfo).toHaveBeenCalledWith({ uid: 'uid-1' }, 'test-access-token', 'test-project', 'tenant', customFetch);
618
- expect(mockedGetToken).toHaveBeenCalledTimes(1);
619
- });
620
- it('updates through the existing endpoint with translated fields and tenant', async () => {
621
- const result = await authWithTenant.updateUser('uid-1', {
622
- displayName: null,
623
- photoURL: null,
624
- phoneNumber: null,
625
- disabled: true
626
- });
627
- expect(result.error).toBeNull();
628
- expect(result.data?.uid).toBe('uid-1');
629
- expect(updateAccountAdmin).toHaveBeenCalledWith('test-project', 'uid-1', {
630
- deleteAttribute: ['DISPLAY_NAME', 'PHOTO_URL'],
631
- deleteProvider: ['phone'],
632
- disableUser: true
633
- }, 'test-access-token', undefined, 'test-tenant-id');
634
- expect(mockedGetAccountInfo).toHaveBeenCalledWith({ uid: 'uid-1' }, 'test-access-token', 'test-project', 'test-tenant-id', undefined);
635
- });
636
- it('deletes without a follow-up lookup and returns void data', async () => {
637
- expect(await authWithTenant.deleteUser('uid-1')).toEqual({
638
- data: undefined,
639
- error: null
640
- });
641
- expect(deleteAccountAdmin).toHaveBeenCalledWith('test-project', 'uid-1', 'test-access-token', undefined, 'test-tenant-id');
642
- expect(mockedGetAccountInfo).not.toHaveBeenCalled();
643
- });
644
- it.each(['', 'a'.repeat(129), null])('rejects invalid UID %s before authentication', async (uid) => {
645
- expect((await auth.updateUser(uid, {})).error).toBeInstanceOf(FirebaseEdgeError);
646
- expect((await auth.deleteUser(uid)).error).toBeInstanceOf(FirebaseEdgeError);
647
- expect(mockedGetToken).not.toHaveBeenCalled();
648
- });
649
- it('rejects invalid create and update properties before authentication', async () => {
650
- expect((await auth.createUser({ email: 'invalid' })).error).toBeInstanceOf(FirebaseEdgeError);
651
- expect((await auth.updateUser('uid', { password: 'short' })).error).toBeInstanceOf(FirebaseEdgeError);
652
- expect(mockedGetToken).not.toHaveBeenCalled();
653
- });
654
- const operations = [
655
- {
656
- name: 'create',
657
- run: () => auth.createUser({}),
658
- endpoint: vi.mocked(createAccountAdmin)
659
- },
660
- {
661
- name: 'update',
662
- run: () => auth.updateUser('uid-1', {}),
663
- endpoint: vi.mocked(updateAccountAdmin)
664
- },
665
- {
666
- name: 'delete',
667
- run: () => auth.deleteUser('uid-1'),
668
- endpoint: vi.mocked(deleteAccountAdmin)
669
- }
670
- ];
671
- describe.each(operations)('$name errors', ({ name, run, endpoint }) => {
672
- it('returns credential errors without a write', async () => {
673
- const error = new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED);
674
- mockedGetToken.mockResolvedValue({ data: null, error });
675
- expect(await run()).toEqual({ data: null, error });
676
- expect(endpoint).not.toHaveBeenCalled();
677
- });
678
- it('guards against missing credentials', async () => {
679
- mockedGetToken.mockResolvedValue({
680
- data: {},
681
- error: null
682
- });
683
- expect((await run()).error?.code).toBe('auth/admin-no-token-returned');
684
- expect(endpoint).not.toHaveBeenCalled();
685
- });
686
- it('preserves API errors as the cause without a readback', async () => {
687
- const cause = new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_USER_NOT_FOUND);
688
- endpoint.mockResolvedValue({ data: null, error: cause });
689
- const result = await run();
690
- expect(result.data).toBeNull();
691
- expect(result.error?.code).toBe(`auth/admin-${name}-user-failed`);
692
- expect(result.error?.cause).toBe(cause);
693
- expect(mockedGetAccountInfo).not.toHaveBeenCalled();
694
- });
695
- it('returns transport exceptions instead of rejecting', async () => {
696
- const cause = new Error('offline');
697
- endpoint.mockRejectedValue(cause);
698
- const result = await run();
699
- expect(result.data).toBeNull();
700
- expect(result.error?.cause).toBe(cause);
701
- });
702
- it('returns unexpected token exceptions', async () => {
703
- mockedGetToken.mockRejectedValue('token failure');
704
- const result = await run();
705
- expect(result.data).toBeNull();
706
- expect(result.error?.code).toBe(`auth/admin-${name}-user-failed`);
707
- });
708
- });
709
- describe.each(operations.slice(0, 2))('$name readback', ({ run, endpoint }) => {
710
- it('requires a UID in the write response', async () => {
711
- endpoint.mockResolvedValue({
712
- data: { localId: '' },
713
- error: null
714
- });
715
- expect((await run()).error).toBeInstanceOf(FirebaseEdgeError);
716
- expect(mockedGetAccountInfo).not.toHaveBeenCalled();
717
- });
718
- it('returns lookup errors', async () => {
719
- const error = new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_USER_NOT_FOUND);
720
- mockedGetAccountInfo.mockResolvedValue({
721
- data: null,
722
- error
723
- });
724
- expect(await run()).toEqual({ data: null, error });
725
- });
726
- it('handles a missing user in the lookup response', async () => {
727
- mockedGetAccountInfo.mockResolvedValue({
728
- data: null,
729
- error: null
730
- });
731
- expect((await run()).error?.code).toBe('auth/admin-user-record-not-found');
732
- });
733
- it('returns conversion errors rather than rejecting', async () => {
734
- mockedGetAccountInfo.mockResolvedValue({
735
- data: { localId: 'uid', customAttributes: '{' },
736
- error: null
737
- });
738
- expect((await run()).error).toBeInstanceOf(FirebaseEdgeError);
739
- });
740
- });
741
- });
742
- describe('listUsers', () => {
743
- const download = vi.mocked(downloadAccount);
744
- beforeEach(() => {
745
- mockedGetToken.mockResolvedValue({
746
- data: mockGoogleTokenResponse,
747
- error: null
748
- });
749
- download.mockResolvedValue({ data: {}, error: null });
750
- });
751
- it('requests the default page and converts the result', async () => {
752
- download.mockResolvedValue({
753
- data: { users: [{ localId: 'uid' }], nextPageToken: 'next' },
754
- error: null
755
- });
756
- const { data, error } = await auth.listUsers();
757
- expect(error).toBeNull();
758
- expect(data?.pageToken).toBe('next');
759
- expect(data?.users[0]).toMatchObject({
760
- uid: 'uid',
761
- emailVerified: false,
762
- disabled: false
763
- });
764
- expect(download).toHaveBeenCalledExactlyOnceWith('test-access-token', 'test-project', 1000, undefined, undefined, undefined);
765
- });
766
- it('forwards pagination, tenant, and custom fetch to the endpoint', async () => {
767
- const customFetch = vi.fn();
768
- const instance = new FirebaseAdminAuth(serviceAccountKey, 'tenant', customFetch);
769
- expect(await instance.listUsers(25, 'opaque+/=')).toEqual({
770
- data: { users: [] },
771
- error: null
772
- });
773
- expect(download).toHaveBeenCalledExactlyOnceWith('test-access-token', 'test-project', 25, 'opaque+/=', 'tenant', customFetch);
774
- expect(mockedGetToken).toHaveBeenCalledWith(serviceAccountKey, customFetch);
775
- });
776
- it('defaults an undefined page size and omits an absent page token', async () => {
777
- expect(await auth.listUsers(undefined)).toEqual({
778
- data: { users: [] },
779
- error: null
780
- });
781
- });
782
- it('preserves an explicitly returned empty page token', async () => {
783
- download.mockResolvedValue({
784
- data: { nextPageToken: '' },
785
- error: null
786
- });
787
- expect(await auth.listUsers()).toEqual({
788
- data: { users: [], pageToken: '' },
789
- error: null
790
- });
791
- });
792
- it.each([0, -1, 1001, 1.5, NaN, Infinity, null, '10'])('rejects invalid page size %s before authentication', async (size) => {
793
- const result = await auth.listUsers(size);
794
- expect(result.data).toBeNull();
795
- expect(result.error?.code).toBe('auth/admin-api-invalid-argument');
796
- expect(mockedGetToken).not.toHaveBeenCalled();
797
- expect(download).not.toHaveBeenCalled();
798
- });
799
- it.each(['', null, 123, {}])('rejects invalid page token %s before authentication', async (pageToken) => {
800
- const result = await auth.listUsers(25, pageToken);
801
- expect(result.data).toBeNull();
802
- expect(result.error?.code).toBe('auth/admin-invalid-page-token');
803
- expect(mockedGetToken).not.toHaveBeenCalled();
804
- expect(download).not.toHaveBeenCalled();
805
- });
806
- it('returns authentication errors without calling the endpoint', async () => {
807
- const error = new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED);
808
- mockedGetToken.mockResolvedValue({ data: null, error });
809
- expect(await auth.listUsers()).toEqual({ data: null, error });
810
- expect(download).not.toHaveBeenCalled();
811
- });
812
- it('uses cached credentials', async () => {
813
- const cache = {
814
- getCache: vi.fn().mockResolvedValue(mockGoogleTokenResponse),
815
- setCache: vi.fn()
816
- };
817
- const instance = new FirebaseAdminAuth(serviceAccountKey, undefined, undefined, cache);
818
- expect((await instance.listUsers()).error).toBeNull();
819
- expect(mockedGetToken).not.toHaveBeenCalled();
820
- expect(cache.getCache).toHaveBeenCalledWith('__cache');
821
- expect(download).toHaveBeenCalledWith('test-access-token', 'test-project', 1000, undefined, undefined, undefined);
822
- });
823
- it('guards against a missing access token', async () => {
824
- mockedGetToken.mockResolvedValue({
825
- data: {},
826
- error: null
827
- });
828
- expect((await auth.listUsers()).error?.code).toBe('auth/admin-no-token-returned');
829
- expect(download).not.toHaveBeenCalled();
830
- });
831
- it('retains a mapped endpoint error as its cause', async () => {
832
- const cause = new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_PERMISSION_DENIED);
833
- download.mockResolvedValue({ data: null, error: cause });
834
- const result = await auth.listUsers();
835
- expect(result.data).toBeNull();
836
- expect(result.error?.code).toBe('auth/admin-list-users-failed');
837
- expect(result.error?.cause).toBe(cause);
838
- });
839
- it.each([
840
- null,
841
- 'not JSON',
842
- { users: [{ localId: 'uid', customAttributes: '{' }] },
843
- { users: [{}] },
844
- { users: 'invalid' }
845
- ])('returns an error for invalid endpoint data %j', async (data) => {
846
- download.mockResolvedValue({ data, error: null });
847
- const result = await auth.listUsers();
848
- expect(result.data).toBeNull();
849
- expect(result.error?.code).toBe('auth/admin-list-users-failed');
850
- });
851
- it('returns unexpected endpoint failures rather than rejecting', async () => {
852
- const cause = new Error('offline');
853
- download.mockRejectedValue(cause);
854
- const result = await auth.listUsers();
855
- expect(result.data).toBeNull();
856
- expect(result.error?.cause).toBe(cause);
857
- });
858
- it('normalizes unexpected authentication failures', async () => {
859
- mockedGetToken.mockRejectedValue('token failure');
860
- const result = await auth.listUsers();
861
- expect(result.data).toBeNull();
862
- expect(result.error?.cause).toBeInstanceOf(Error);
863
- });
864
- });
865
- describe('getUser', () => {
866
- it('returns error when getToken returns an error', async () => {
867
- mockedGetToken.mockResolvedValueOnce({
868
- data: null,
869
- error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED)
870
- });
871
- const result = await auth.getUser('uid-1');
872
- expect(mockedGetToken).toHaveBeenCalled();
873
- expect(result.data).toBeNull();
874
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
875
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED
876
- .code);
877
- });
878
- it('returns error when getToken does not return a token', async () => {
879
- mockedGetToken.mockResolvedValueOnce({
880
- data: null,
881
- error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED)
882
- });
883
- const result = await auth.getUser('uid-1');
884
- expect(result.data).toBeNull();
885
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
886
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED
887
- .code);
888
- });
889
- it('returns user when everything succeeds', async () => {
890
- mockedGetToken.mockResolvedValueOnce({
891
- data: mockGoogleTokenResponse,
892
- error: null
893
- });
894
- mockedGetAccountInfo.mockResolvedValueOnce({
895
- data: mockUserRecord,
896
- error: null
897
- });
898
- const result = await auth.getUser('uid-1');
899
- expect(mockedGetToken).toHaveBeenCalledWith(serviceAccountKey, undefined);
900
- expect(mockedGetAccountInfo).toHaveBeenCalledWith({ uid: 'uid-1' }, 'test-access-token', 'test-project', undefined, undefined);
901
- expect(result.data).toEqual(mockUserRecord);
902
- expect(result.error).toBeNull();
903
- });
904
- it('returns error when getAccountInfoByUid fails', async () => {
905
- mockedGetToken.mockResolvedValueOnce({
906
- data: mockGoogleTokenResponse,
907
- error: null
908
- });
909
- const error = new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_USER_NOT_FOUND);
910
- mockedGetAccountInfo.mockResolvedValueOnce({
911
- data: null,
912
- error
913
- });
914
- const result = await auth.getUser('uid-1');
915
- expect(result.data).toBeNull();
916
- expect(result.error).toEqual(error);
917
- });
918
- });
919
- describe('verifyIdToken', () => {
920
- it('returns error when verifyJWT fails', async () => {
921
- mockedVerifyJWT.mockResolvedValueOnce({
922
- data: null,
923
- error: new Error('bad token')
924
- });
925
- const result = await auth.verifyIdToken('id-token');
926
- expect(mockedVerifyJWT).toHaveBeenCalledWith('id-token', 'test-project', undefined);
927
- expect(result.data).toBeNull();
928
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
929
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_ID_TOKEN_VERIFY_FAILED.code);
930
- });
931
- it('returns decoded token when not checking revoked', async () => {
932
- mockedVerifyJWT.mockResolvedValueOnce({
933
- data: mockFirebasePayload,
934
- error: null
935
- });
936
- const result = await auth.verifyIdToken('id-token', false);
937
- expect(result.data).toEqual(mockFirebasePayload);
938
- expect(result.error).toBeNull();
939
- });
940
- it('returns error when user lookup fails during revoked check', async () => {
941
- mockedVerifyJWT.mockResolvedValueOnce({
942
- data: mockFirebasePayload,
943
- error: null
944
- });
945
- const userError = new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_INTERNAL_ERROR);
946
- mockedGetToken.mockResolvedValueOnce({
947
- data: mockGoogleTokenResponse,
948
- error: null
949
- });
950
- mockedGetAccountInfo.mockResolvedValueOnce({
951
- data: null,
952
- error: userError
953
- });
954
- const result = await auth.verifyIdToken('id-token', true);
955
- expect(result.data).toBeNull();
956
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
957
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_USER_LOOKUP_FAILED.code);
958
- });
959
- it('returns ERR_NO_USER when user is null during revoked check', async () => {
960
- mockedVerifyJWT.mockResolvedValueOnce({
961
- data: mockFirebasePayload,
962
- error: null
963
- });
964
- mockedGetToken.mockResolvedValueOnce({
965
- data: mockGoogleTokenResponse,
966
- error: null
967
- });
968
- mockedGetAccountInfo.mockResolvedValueOnce({
969
- data: null,
970
- error: null
971
- });
972
- const result = await auth.verifyIdToken('id-token', true);
973
- expect(result.data).toBeNull();
974
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
975
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_USER_RECORD_NOT_FOUND.code);
976
- });
977
- it('returns ERR_USER_DISABLED when user.disabled is true', async () => {
978
- mockedVerifyJWT.mockResolvedValueOnce({
979
- data: mockFirebasePayload,
980
- error: null
981
- });
982
- mockedGetToken.mockResolvedValueOnce({
983
- data: mockGoogleTokenResponse,
984
- error: null
985
- });
986
- mockedGetAccountInfo.mockResolvedValueOnce({
987
- data: { ...mockUserRecord, disabled: true },
988
- error: null
989
- });
990
- const result = await auth.verifyIdToken('id-token', true);
991
- expect(result.data).toBeNull();
992
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
993
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_USER_DISABLED.code);
994
- });
995
- it('returns ERR_TOKEN_REVOKED when auth_time < tokensValidAfterTime', async () => {
996
- mockedVerifyJWT.mockResolvedValueOnce({
997
- data: mockFirebasePayload,
998
- error: null
999
- });
1000
- mockedGetToken.mockResolvedValueOnce({
1001
- data: mockGoogleTokenResponse,
1002
- error: null
1003
- });
1004
- // tokensValidAfterTime far in the future compared to auth_time
1005
- mockedGetAccountInfo.mockResolvedValueOnce({
1006
- data: {
1007
- ...mockUserRecord,
1008
- disabled: false,
1009
- validSince: '2000000'
1010
- },
1011
- error: null
1012
- });
1013
- const result = await auth.verifyIdToken('id-token', true);
1014
- expect(result.data).toBeNull();
1015
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1016
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_ID_TOKEN_REVOKED.code);
1017
- });
1018
- it('returns decoded token when not revoked', async () => {
1019
- const mockPayloadWithLaterAuthTime = {
1020
- ...mockFirebasePayload,
1021
- auth_time: 2000
1022
- };
1023
- mockedVerifyJWT.mockResolvedValueOnce({
1024
- data: mockPayloadWithLaterAuthTime,
1025
- error: null
1026
- });
1027
- mockedGetToken.mockResolvedValueOnce({
1028
- data: mockGoogleTokenResponse,
1029
- error: null
1030
- });
1031
- mockedGetAccountInfo.mockResolvedValueOnce({
1032
- data: {
1033
- ...mockUserRecord,
1034
- disabled: false,
1035
- validSince: '1000'
1036
- },
1037
- error: null
1038
- });
1039
- const result = await auth.verifyIdToken('id-token', true);
1040
- expect(result.data).toEqual(mockPayloadWithLaterAuthTime);
1041
- expect(result.error).toBeNull();
1042
- });
1043
- it('returns error when token has no decoded payload', async () => {
1044
- mockedVerifyJWT.mockResolvedValueOnce({
1045
- data: null,
1046
- error: new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_INVALID_ID_TOKEN)
1047
- });
1048
- const result = await auth.verifyIdToken('id-token');
1049
- expect(result.data).toBeNull();
1050
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1051
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_ID_TOKEN_VERIFY_FAILED.code);
1052
- });
1053
- it('returns error when tenant ID does not match', async () => {
1054
- const mockPayloadWithDifferentTenant = {
1055
- ...mockFirebasePayload,
1056
- firebase: {
1057
- ...mockFirebasePayload.firebase,
1058
- tenant: 'different-tenant-id'
1059
- }
1060
- };
1061
- mockedVerifyJWT.mockResolvedValueOnce({
1062
- data: mockPayloadWithDifferentTenant,
1063
- error: null
1064
- });
1065
- const result = await authWithTenant.verifyIdToken('id-token');
1066
- expect(result.data).toBeNull();
1067
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1068
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_TENANT_ID_INVALID.code);
1069
- });
1070
- it('returns success when tenant ID matches', async () => {
1071
- const mockPayloadWithCorrectTenant = {
1072
- ...mockFirebasePayload,
1073
- firebase: {
1074
- ...mockFirebasePayload.firebase,
1075
- tenant: 'test-tenant-id'
1076
- }
1077
- };
1078
- mockedVerifyJWT.mockResolvedValueOnce({
1079
- data: mockPayloadWithCorrectTenant,
1080
- error: null
1081
- });
1082
- const result = await authWithTenant.verifyIdToken('id-token', false);
1083
- expect(result.data).toEqual(mockPayloadWithCorrectTenant);
1084
- expect(result.error).toBeNull();
1085
- });
1086
- });
1087
- describe.each([
1088
- ['generatePasswordResetLink', 'PASSWORD_RESET'],
1089
- ['generateEmailVerificationLink', 'VERIFY_EMAIL'],
1090
- ['generateSignInWithEmailLink', 'EMAIL_SIGNIN']
1091
- ])('%s', (method, requestType) => {
1092
- const settings = {
1093
- url: 'https://example.com/finish',
1094
- handleCodeInApp: true
1095
- };
1096
- it('returns the generated link and forwards credentials, settings, tenant and fetch', async () => {
1097
- const fetchFn = vi.fn();
1098
- const admin = new FirebaseAdminAuth(serviceAccountKey, 'tenant', fetchFn);
1099
- mockedGetToken.mockResolvedValue({
1100
- data: mockGoogleTokenResponse,
1101
- error: null
1102
- });
1103
- vi.mocked(generateEmailActionLink).mockResolvedValue({
1104
- data: 'https://example.com/action',
1105
- error: null
1106
- });
1107
- expect(await admin[method]('person@example.com', settings)).toEqual({ data: 'https://example.com/action', error: null });
1108
- expect(generateEmailActionLink).toHaveBeenCalledWith('test-project', {
1109
- requestType,
1110
- email: 'person@example.com',
1111
- returnOobLink: true,
1112
- continueUrl: settings.url,
1113
- canHandleCodeInApp: true
1114
- }, 'test-access-token', fetchFn, 'tenant');
1115
- });
1116
- it('rejects invalid input before obtaining credentials', async () => {
1117
- expect((await auth[method]('invalid', settings)).error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_API_INVALID_ARGUMENT.code);
1118
- expect(mockedGetToken).not.toHaveBeenCalled();
1119
- expect(generateEmailActionLink).not.toHaveBeenCalled();
1120
- });
1121
- it('returns authentication errors without calling the endpoint', async () => {
1122
- mockedGetToken.mockResolvedValue({
1123
- data: null,
1124
- error: new Error('credentials')
1125
- });
1126
- expect((await auth[method]('person@example.com', settings)).error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED
1127
- .code);
1128
- expect(generateEmailActionLink).not.toHaveBeenCalled();
1129
- });
1130
- it('wraps endpoint errors and preserves the cause', async () => {
1131
- const cause = new Error('email not found');
1132
- mockedGetToken.mockResolvedValue({
1133
- data: mockGoogleTokenResponse,
1134
- error: null
1135
- });
1136
- vi.mocked(generateEmailActionLink).mockResolvedValue({
1137
- data: null,
1138
- error: cause
1139
- });
1140
- const result = await auth[method]('person@example.com', settings);
1141
- expect(result.error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_EMAIL_ACTION_LINK_FAILED.code);
1142
- expect(result.error?.cause).toBe(cause);
1143
- });
1144
- it('returns unexpected failures using the package error convention', async () => {
1145
- mockedGetToken.mockResolvedValue({
1146
- data: mockGoogleTokenResponse,
1147
- error: null
1148
- });
1149
- vi.mocked(generateEmailActionLink).mockRejectedValue(new Error('network'));
1150
- expect((await auth[method]('person@example.com', settings)).error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_EMAIL_ACTION_LINK_FAILED.code);
1151
- });
1152
- });
1153
- it.each([
1154
- 'generatePasswordResetLink',
1155
- 'generateEmailVerificationLink'
1156
- ])('%s allows omitted settings', async (method) => {
1157
- mockedGetToken.mockResolvedValue({
1158
- data: mockGoogleTokenResponse,
1159
- error: null
1160
- });
1161
- vi.mocked(generateEmailActionLink).mockResolvedValue({
1162
- data: 'https://example.com/action',
1163
- error: null
1164
- });
1165
- expect((await auth[method]('person@example.com')).error).toBeNull();
1166
- expect(generateEmailActionLink).toHaveBeenCalledWith('test-project', expect.not.objectContaining({ continueUrl: expect.anything() }), 'test-access-token', undefined, undefined);
1167
- });
1168
- it('requires settings when generating an email sign-in link', async () => {
1169
- const result =
1170
- // @ts-expect-error Settings are required for email sign-in.
1171
- await auth.generateSignInWithEmailLink('person@example.com');
1172
- expect(result.error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_API_INVALID_ARGUMENT.code);
1173
- expect(mockedGetToken).not.toHaveBeenCalled();
1174
- });
1175
- it.each([
1176
- 'generatePasswordResetLink',
1177
- 'generateEmailVerificationLink',
1178
- 'generateSignInWithEmailLink',
1179
- 'createSessionCookie'
1180
- ])('%s rejects missing access tokens', async (method) => {
1181
- mockedGetToken.mockResolvedValue({
1182
- data: { ...mockGoogleTokenResponse, access_token: '' },
1183
- error: null
1184
- });
1185
- const result = method === 'createSessionCookie'
1186
- ? await auth.createSessionCookie('id-token', {
1187
- expiresIn: 300000
1188
- })
1189
- : await auth[method]('person@example.com', {
1190
- url: 'https://example.com'
1191
- });
1192
- expect(result.error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_NO_TOKEN_RETURNED.code);
1193
- expect(generateEmailActionLink).not.toHaveBeenCalled();
1194
- expect(mockedCreateSessionCookieEndpoint).not.toHaveBeenCalled();
1195
- });
1196
- describe('createSessionCookie', () => {
1197
- it.each([
1198
- undefined,
1199
- null,
1200
- 3600000,
1201
- {},
1202
- { expiresIn: '3600000' },
1203
- { expiresIn: NaN },
1204
- { expiresIn: Infinity },
1205
- { expiresIn: 299999 },
1206
- { expiresIn: 1209600001 }
1207
- ])('rejects invalid options %j before authentication', async (options) => {
1208
- const result = await auth.createSessionCookie('id-token', options);
1209
- expect(result.error?.code).toBe(FirebaseAdminAuthErrorInfo
1210
- .ADMIN_SESSION_COOKIE_DURATION_INVALID.code);
1211
- expect(mockedGetToken).not.toHaveBeenCalled();
1212
- });
1213
- it.each(['', null, 1])('rejects invalid ID token %s', async (idToken) => {
1214
- const result = await auth.createSessionCookie(idToken, { expiresIn: 300000 });
1215
- expect(result.error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_ID_TOKEN_INVALID.code);
1216
- expect(mockedGetToken).not.toHaveBeenCalled();
1217
- });
1218
- it.each([300000, 1209600000])('accepts boundary lifetime %s and forwards tenant and fetch', async (expiresIn) => {
1219
- const fetchFn = vi.fn();
1220
- const admin = new FirebaseAdminAuth(serviceAccountKey, 'tenant', fetchFn);
1221
- mockedGetToken.mockResolvedValue({
1222
- data: mockGoogleTokenResponse,
1223
- error: null
1224
- });
1225
- mockedCreateSessionCookieEndpoint.mockResolvedValue({
1226
- data: 'cookie',
1227
- error: null
1228
- });
1229
- expect(await admin.createSessionCookie('id-token', { expiresIn })).toEqual({ data: 'cookie', error: null });
1230
- expect(mockedCreateSessionCookieEndpoint).toHaveBeenCalledWith('id-token', 'test-access-token', 'test-project', expiresIn, 'tenant', fetchFn);
1231
- });
1232
- it('returns an error for an empty cookie response', async () => {
1233
- mockedGetToken.mockResolvedValue({
1234
- data: mockGoogleTokenResponse,
1235
- error: null
1236
- });
1237
- mockedCreateSessionCookieEndpoint.mockResolvedValue({
1238
- data: null,
1239
- error: null
1240
- });
1241
- const result = await auth.createSessionCookie('id-token', {
1242
- expiresIn: 300000
1243
- });
1244
- expect(result.error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_SESSION_COOKIE_CREATE_FAILED
1245
- .code);
1246
- });
1247
- it('wraps unexpected endpoint failures', async () => {
1248
- mockedGetToken.mockResolvedValue({
1249
- data: mockGoogleTokenResponse,
1250
- error: null
1251
- });
1252
- mockedCreateSessionCookieEndpoint.mockRejectedValue(new Error('network'));
1253
- const result = await auth.createSessionCookie('id-token', {
1254
- expiresIn: 300000
1255
- });
1256
- expect(result.error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_SESSION_COOKIE_CREATE_FAILED
1257
- .code);
1258
- });
1259
- it('returns error when getToken fails', async () => {
1260
- mockedGetToken.mockResolvedValueOnce({
1261
- data: null,
1262
- error: new Error('unauthorized')
1263
- });
1264
- const result = await auth.createSessionCookie('id-token', {
1265
- expiresIn: 3600000
1266
- });
1267
- expect(result.data).toBeNull();
1268
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1269
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED
1270
- .code);
1271
- });
1272
- it('returns error when token is missing', async () => {
1273
- mockedGetToken.mockResolvedValueOnce({
1274
- data: null,
1275
- error: new FirebaseEdgeError(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED)
1276
- });
1277
- const result = await auth.createSessionCookie('id-token', {
1278
- expiresIn: 3600000
1279
- });
1280
- expect(result.data).toBeNull();
1281
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1282
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_SERVICE_ACCOUNT_TOKEN_FAILED
1283
- .code);
1284
- });
1285
- it('returns error when endpoint returns error', async () => {
1286
- mockedGetToken.mockResolvedValueOnce({
1287
- data: mockGoogleTokenResponse,
1288
- error: null
1289
- });
1290
- const endpointError = new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_INVALID_ARGUMENT);
1291
- mockedCreateSessionCookieEndpoint.mockResolvedValueOnce({
1292
- data: null,
1293
- error: endpointError
1294
- });
1295
- const result = await auth.createSessionCookie('id-token', {
1296
- expiresIn: 3600000
1297
- });
1298
- expect(mockedCreateSessionCookieEndpoint).toHaveBeenCalledWith('id-token', 'test-access-token', 'test-project', 3600000, undefined, undefined);
1299
- expect(result.data).toBeNull();
1300
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1301
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_SESSION_COOKIE_CREATE_FAILED
1302
- .code);
1303
- });
1304
- it('returns session cookie data on success', async () => {
1305
- mockedGetToken.mockResolvedValueOnce({
1306
- data: mockGoogleTokenResponse,
1307
- error: null
1308
- });
1309
- const cookieData = 'cookie-value';
1310
- mockedCreateSessionCookieEndpoint.mockResolvedValueOnce({
1311
- data: cookieData,
1312
- error: null
1313
- });
1314
- const result = await auth.createSessionCookie('id-token', {
1315
- expiresIn: 3600000
1316
- });
1317
- expect(result.data).toEqual(cookieData);
1318
- expect(result.error).toBeNull();
1319
- });
1320
- });
1321
- describe('verifySessionCookie', () => {
1322
- it('rejects disabled users when revocation checking is enabled', async () => {
1323
- mockedVerifySessionJWT.mockResolvedValue({
1324
- data: mockFirebasePayload,
1325
- error: null
1326
- });
1327
- vi.spyOn(auth, 'getUser').mockResolvedValue({
1328
- data: { ...mockUserRecord, disabled: true },
1329
- error: null
1330
- });
1331
- expect((await auth.verifySessionCookie('cookie', true)).error?.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_USER_DISABLED.code);
1332
- });
1333
- it.each([
1334
- [
1335
- '1001',
1336
- FirebaseAdminAuthErrorInfo.ADMIN_SESSION_COOKIE_REVOKED.code
1337
- ],
1338
- ['1000', undefined],
1339
- ['999', undefined],
1340
- [undefined, undefined]
1341
- ])('checks auth_time against validSince %s, not issuance time', async (validSince, expectedCode) => {
1342
- mockedVerifySessionJWT.mockResolvedValue({
1343
- data: { ...mockFirebasePayload, iat: 1500 },
1344
- error: null
1345
- });
1346
- vi.spyOn(auth, 'getUser').mockResolvedValue({
1347
- data: { ...mockUserRecord, validSince },
1348
- error: null
1349
- });
1350
- const result = await auth.verifySessionCookie('cookie', true);
1351
- expect(result.error?.code).toBe(expectedCode);
1352
- expect(result.data === null).toBe(Boolean(expectedCode));
1353
- });
1354
- it('skips the user lookup by default', async () => {
1355
- mockedVerifySessionJWT.mockResolvedValue({
1356
- data: mockFirebasePayload,
1357
- error: null
1358
- });
1359
- const lookup = vi.spyOn(auth, 'getUser');
1360
- expect(await auth.verifySessionCookie('cookie')).toEqual({
1361
- data: mockFirebasePayload,
1362
- error: null
1363
- });
1364
- expect(lookup).not.toHaveBeenCalled();
1365
- });
1366
- it('returns error when verifySessionJWT fails', async () => {
1367
- mockedVerifySessionJWT.mockResolvedValueOnce({
1368
- data: null,
1369
- error: new Error('bad session token')
1370
- });
1371
- const result = await auth.verifySessionCookie('session-cookie');
1372
- expect(result.data).toBeNull();
1373
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1374
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_SESSION_COOKIE_VERIFY_FAILED
1375
- .code);
1376
- });
1377
- it('returns data when not checking revoked', async () => {
1378
- mockedVerifySessionJWT.mockResolvedValueOnce({
1379
- data: mockFirebasePayload,
1380
- error: null
1381
- });
1382
- const result = await auth.verifySessionCookie('session-cookie', false);
1383
- expect(result.data).toEqual(mockFirebasePayload);
1384
- expect(result.error).toBeNull();
1385
- });
1386
- it('returns error when user lookup fails during revoked check', async () => {
1387
- mockedVerifySessionJWT.mockResolvedValueOnce({
1388
- data: mockFirebasePayload,
1389
- error: null
1390
- });
1391
- mockedGetToken.mockResolvedValueOnce({
1392
- data: mockGoogleTokenResponse,
1393
- error: null
1394
- });
1395
- const error = new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_INTERNAL_ERROR);
1396
- mockedGetAccountInfo.mockResolvedValueOnce({
1397
- data: null,
1398
- error
1399
- });
1400
- const result = await auth.verifySessionCookie('session-cookie', true);
1401
- expect(result.data).toBeNull();
1402
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1403
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_USER_LOOKUP_FAILED.code);
1404
- });
1405
- it('returns ERR_NO_USER when user is null during revoked check', async () => {
1406
- mockedVerifySessionJWT.mockResolvedValueOnce({
1407
- data: mockFirebasePayload,
1408
- error: null
1409
- });
1410
- mockedGetToken.mockResolvedValueOnce({
1411
- data: mockGoogleTokenResponse,
1412
- error: null
1413
- });
1414
- mockedGetAccountInfo.mockResolvedValueOnce({
1415
- data: null,
1416
- error: null
1417
- });
1418
- const result = await auth.verifySessionCookie('session-cookie', true);
1419
- expect(result.data).toBeNull();
1420
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1421
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_USER_RECORD_NOT_FOUND.code);
1422
- });
1423
- it('returns decoded data when revoked check passes', async () => {
1424
- mockedVerifySessionJWT.mockResolvedValueOnce({
1425
- data: mockFirebasePayload,
1426
- error: null
1427
- });
1428
- mockedGetToken.mockResolvedValueOnce({
1429
- data: mockGoogleTokenResponse,
1430
- error: null
1431
- });
1432
- mockedGetAccountInfo.mockResolvedValueOnce({
1433
- data: mockUserRecord,
1434
- error: null
1435
- });
1436
- const result = await auth.verifySessionCookie('session-cookie', true);
1437
- expect(result.data).toEqual(mockFirebasePayload);
1438
- expect(result.error).toBeNull();
1439
- });
1440
- it('returns error when no decoded data returned', async () => {
1441
- mockedVerifySessionJWT.mockResolvedValueOnce({
1442
- data: null,
1443
- error: new FirebaseEdgeError(FirebaseEndpointErrorInfo.ENDPOINT_INVALID_SESSION_COOKIE)
1444
- });
1445
- const result = await auth.verifySessionCookie('session-cookie');
1446
- expect(result.data).toBeNull();
1447
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1448
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_SESSION_COOKIE_VERIFY_FAILED
1449
- .code);
1450
- });
1451
- it('returns error when tenant ID does not match', async () => {
1452
- const mockPayloadWithDifferentTenant = {
1453
- ...mockFirebasePayload,
1454
- firebase: {
1455
- ...mockFirebasePayload.firebase,
1456
- tenant: 'wrong-tenant-id'
1457
- }
1458
- };
1459
- mockedVerifySessionJWT.mockResolvedValueOnce({
1460
- data: mockPayloadWithDifferentTenant,
1461
- error: null
1462
- });
1463
- const result = await authWithTenant.verifySessionCookie('session-cookie');
1464
- expect(result.data).toBeNull();
1465
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1466
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_TENANT_ID_INVALID.code);
1467
- });
1468
- it('returns success when tenant ID matches', async () => {
1469
- const mockPayloadWithCorrectTenant = {
1470
- ...mockFirebasePayload,
1471
- firebase: {
1472
- ...mockFirebasePayload.firebase,
1473
- tenant: 'test-tenant-id'
1474
- }
1475
- };
1476
- mockedVerifySessionJWT.mockResolvedValueOnce({
1477
- data: mockPayloadWithCorrectTenant,
1478
- error: null
1479
- });
1480
- const result = await authWithTenant.verifySessionCookie('session-cookie', false);
1481
- expect(result.data).toEqual(mockPayloadWithCorrectTenant);
1482
- expect(result.error).toBeNull();
1483
- });
1484
- });
1485
- describe('createCustomToken', () => {
1486
- it('returns error when signJWTCustomToken fails', async () => {
1487
- mockedSignJWTCustomToken.mockResolvedValueOnce({
1488
- data: null,
1489
- error: new Error('sign failed')
1490
- });
1491
- const result = await auth.createCustomToken('uid-1');
1492
- expect(mockedSignJWTCustomToken).toHaveBeenCalledWith('uid-1', serviceAccountKey, {});
1493
- expect(result.data).toBeNull();
1494
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1495
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_CUSTOM_TOKEN_CREATE_FAILED.code);
1496
- });
1497
- it('returns error when no data is returned', async () => {
1498
- mockedSignJWTCustomToken.mockResolvedValueOnce({
1499
- data: null,
1500
- error: new FirebaseEdgeError(JWTErrorInfo.JWT_UNKNOWN_SIGNING_ERROR)
1501
- });
1502
- const result = await auth.createCustomToken('uid-1');
1503
- expect(result.data).toBeNull();
1504
- expect(result.error).toBeInstanceOf(FirebaseEdgeError);
1505
- expect(result.error.code).toBe(FirebaseAdminAuthErrorInfo.ADMIN_CUSTOM_TOKEN_CREATE_FAILED.code);
1506
- });
1507
- it('returns token when successful', async () => {
1508
- mockedSignJWTCustomToken.mockResolvedValueOnce({
1509
- data: 'custom-token',
1510
- error: null
1511
- });
1512
- const claims = { role: 'admin' };
1513
- const result = await auth.createCustomToken('uid-1', claims);
1514
- expect(mockedSignJWTCustomToken).toHaveBeenCalledWith('uid-1', serviceAccountKey, claims);
1515
- expect(result.data).toBe('custom-token');
1516
- expect(result.error).toBeNull();
1517
- });
1518
- it('includes tenant_id claim when tenant is specified', async () => {
1519
- mockedSignJWTCustomToken.mockResolvedValueOnce({
1520
- data: 'custom-token-with-tenant',
1521
- error: null
1522
- });
1523
- const claims = { role: 'admin' };
1524
- const result = await authWithTenant.createCustomToken('uid-1', claims);
1525
- expect(mockedSignJWTCustomToken).toHaveBeenCalledWith('uid-1', serviceAccountKey, { ...claims, tenant_id: 'test-tenant-id' });
1526
- expect(result.data).toBe('custom-token-with-tenant');
1527
- expect(result.error).toBeNull();
1528
- });
1529
- it('does not add tenant_id when no tenant specified', async () => {
1530
- mockedSignJWTCustomToken.mockResolvedValueOnce({
1531
- data: 'custom-token',
1532
- error: null
1533
- });
1534
- const claims = { role: 'user' };
1535
- const result = await auth.createCustomToken('uid-1', claims);
1536
- expect(mockedSignJWTCustomToken).toHaveBeenCalledWith('uid-1', serviceAccountKey, claims);
1537
- expect(result.data).toBe('custom-token');
1538
- expect(result.error).toBeNull();
1539
- });
1540
- });
1541
- });
1542
- //# sourceMappingURL=firebase-admin-auth.test.js.map