Auth+Combine.swift 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. // Copyright 2020 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #if canImport(Combine) && swift(>=5.0)
  15. import Foundation
  16. import Combine
  17. import FirebaseAuth
  18. // Make this class discoverable from Objective-C. Don't instantiate directly.
  19. @objc(FIRCombineAuthLibrary) private class __CombineAuthLibrary: NSObject {}
  20. @available(swift 5.0)
  21. @available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)
  22. public extension Auth {
  23. // MARK: - Authentication State Management
  24. /// Registers a publisher that publishes authentication state changes.
  25. ///
  26. /// The publisher emits values when:
  27. ///
  28. /// - It is registered,
  29. /// - a user with a different UID from the current user has signed in, or
  30. /// - the current user has signed out.
  31. ///
  32. /// The publisher will emit events on the **main** thread.
  33. ///
  34. /// - Returns: A publisher emitting a `User` instance (if the user has signed in) or `nil` (if
  35. /// the user has signed out).
  36. /// The publisher will emit on the *main* thread.
  37. func authStateDidChangePublisher() -> AnyPublisher<User?, Never> {
  38. let subject = PassthroughSubject<User?, Never>()
  39. let handle = addStateDidChangeListener { auth, user in
  40. subject.send(user)
  41. }
  42. return subject
  43. .handleEvents(receiveCancel: {
  44. self.removeStateDidChangeListener(handle)
  45. })
  46. .eraseToAnyPublisher()
  47. }
  48. /// Registers a publisher that publishes ID token state changes.
  49. ///
  50. /// The publisher emits values when:
  51. ///
  52. /// - It is registered,
  53. /// - a user with a different UID from the current user has signed in,
  54. /// - the ID token of the current user has been refreshed, or
  55. /// - the current user has signed out.
  56. ///
  57. /// The publisher will emit events on the **main** thread.
  58. ///
  59. /// - Returns: A publisher emitting a `User` instance (if a different user is signed in or
  60. /// the ID token of the current user has changed) or `nil` (if the user has signed out).
  61. /// The publisher will emit on the *main* thread.
  62. func idTokenDidChangePublisher() -> AnyPublisher<User?, Never> {
  63. let subject = PassthroughSubject<User?, Never>()
  64. let handle = addIDTokenDidChangeListener { auth, user in
  65. subject.send(user)
  66. }
  67. return subject
  68. .handleEvents(receiveCancel: {
  69. self.removeIDTokenDidChangeListener(handle)
  70. })
  71. .eraseToAnyPublisher()
  72. }
  73. /// Sets the `currentUser` on the calling Auth instance to the provided `user` object.
  74. ///
  75. /// The publisher will emit events on the **main** thread.
  76. ///
  77. /// - Parameter user: The user object to be set as the current user of the calling Auth
  78. /// instance.
  79. /// - Returns: A publisher that emits when the user of the calling Auth instance has been
  80. /// updated or
  81. /// an error was encountered. The publisher will emit on the **main** thread.
  82. @discardableResult
  83. func updateCurrentUser(_ user: User) -> Future<Void, Error> {
  84. Future<Void, Error> { promise in
  85. self.updateCurrentUser(user) { error in
  86. if let error = error {
  87. promise(.failure(error))
  88. } else {
  89. promise(.success(()))
  90. }
  91. }
  92. }
  93. }
  94. // MARK: - Anonymous Authentication
  95. /// Asynchronously creates an anonymous user and assigns it as the calling Auth instance's
  96. /// current user.
  97. ///
  98. /// If there is already an anonymous user signed in, that user will be returned instead.
  99. /// If there is any other existing user signed in, that user will be signed out.
  100. ///
  101. /// The publisher will emit events on the **main** thread.
  102. ///
  103. /// - Returns: A publisher that emits the result of the sign in flow. The publisher will emit on
  104. /// the *main* thread.
  105. /// - Remark:
  106. /// Possible error codes:
  107. /// - `AuthErrorCodeOperationNotAllowed` - Indicates that anonymous accounts are
  108. /// not enabled. Enable them in the Auth section of the Firebase console.
  109. ///
  110. /// See `AuthErrors` for a list of error codes that are common to all API methods
  111. @discardableResult
  112. func signInAnonymously() -> Future<AuthDataResult, Error> {
  113. Future<AuthDataResult, Error> { promise in
  114. self.signInAnonymously { authDataResult, error in
  115. if let error = error {
  116. promise(.failure(error))
  117. } else if let authDataResult = authDataResult {
  118. promise(.success(authDataResult))
  119. }
  120. }
  121. }
  122. }
  123. // MARK: - Email/Password Authentication
  124. /// Creates and, on success, signs in a user with the given email address and password.
  125. ///
  126. /// The publisher will emit events on the **main** thread.
  127. ///
  128. /// - Parameters:
  129. /// - email: The user's email address.
  130. /// - password: The user's desired password.
  131. /// - Returns: A publisher that emits the result of the sign in flow. The publisher will emit on
  132. /// the *main* thread.
  133. /// - Remark:
  134. /// Possible error codes:
  135. /// - `AuthErrorCodeInvalidEmail` - Indicates the email address is malformed.
  136. /// - `AuthErrorCodeEmailAlreadyInUse` - Indicates the email used to attempt sign up
  137. /// already exists. Call fetchProvidersForEmail to check which sign-in mechanisms the user
  138. /// used, and prompt the user to sign in with one of those.
  139. /// - `AuthErrorCodeOperationNotAllowed` - Indicates that email and password accounts
  140. /// are not enabled. Enable them in the Auth section of the Firebase console.
  141. /// - `AuthErrorCodeWeakPassword` - Indicates an attempt to set a password that is
  142. /// considered too weak. The NSLocalizedFailureReasonErrorKey field in the NSError.userInfo
  143. /// dictionary object will contain more detailed explanation that can be shown to the user.
  144. ///
  145. /// See `AuthErrors` for a list of error codes that are common to all API methods
  146. @discardableResult
  147. func createUser(withEmail email: String,
  148. password: String) -> Future<AuthDataResult, Error> {
  149. Future<AuthDataResult, Error> { promise in
  150. self.createUser(withEmail: email, password: password) { authDataResult, error in
  151. if let error = error {
  152. promise(.failure(error))
  153. } else if let authDataResult = authDataResult {
  154. promise(.success(authDataResult))
  155. }
  156. }
  157. }
  158. }
  159. /// Signs in a user with the given email address and password.
  160. ///
  161. /// The publisher will emit events on the **main** thread.
  162. ///
  163. /// - Parameters:
  164. /// - email: The user's email address.
  165. /// - password: The user's password.
  166. /// - Returns: A publisher that emits the result of the sign in flow. The publisher will emit on
  167. /// the *main* thread.
  168. /// - Remark:
  169. /// Possible error codes:
  170. /// - `AuthErrorCodeOperationNotAllowed` - Indicates that email and password
  171. /// accounts are not enabled. Enable them in the Auth section of the
  172. /// Firebase console.
  173. /// - `AuthErrorCodeUserDisabled` - Indicates the user's account is disabled.
  174. /// - `AuthErrorCodeWrongPassword` - Indicates the user attempted
  175. /// sign in with an incorrect password.
  176. /// - `AuthErrorCodeInvalidEmail` - Indicates the email address is malformed.
  177. ///
  178. /// See `AuthErrors` for a list of error codes that are common to all API methods
  179. @discardableResult
  180. func signIn(withEmail email: String,
  181. password: String) -> Future<AuthDataResult, Error> {
  182. Future<AuthDataResult, Error> { promise in
  183. self.signIn(withEmail: email, password: password) { authDataResult, error in
  184. if let error = error {
  185. promise(.failure(error))
  186. } else if let authDataResult = authDataResult {
  187. promise(.success(authDataResult))
  188. }
  189. }
  190. }
  191. }
  192. // MARK: - Email/Link Authentication
  193. /// Signs in using an email address and email sign-in link.
  194. ///
  195. /// The publisher will emit events on the **main** thread.
  196. ///
  197. /// - Parameters:
  198. /// - email: The user's email address.
  199. /// - link: The email sign-in link.
  200. /// - Returns: A publisher that emits the result of the sign in flow. The publisher will emit on
  201. /// the *main* thread.
  202. /// - Remark:
  203. /// Possible error codes:
  204. /// - `AuthErrorCodeOperationNotAllowed` - Indicates that email and password
  205. /// accounts are not enabled. Enable them in the Auth section of the
  206. /// Firebase console.
  207. /// - `AuthErrorCodeUserDisabled` - Indicates the user's account is disabled.
  208. /// - `AuthErrorCodeInvalidEmail` - Indicates the email address is malformed.
  209. ///
  210. /// See `AuthErrors` for a list of error codes that are common to all API methods
  211. @available(watchOS, unavailable)
  212. @discardableResult
  213. func signIn(withEmail email: String,
  214. link: String) -> Future<AuthDataResult, Error> {
  215. Future<AuthDataResult, Error> { promise in
  216. self.signIn(withEmail: email, link: link) { authDataResult, error in
  217. if let error = error {
  218. promise(.failure(error))
  219. } else if let authDataResult = authDataResult {
  220. promise(.success(authDataResult))
  221. }
  222. }
  223. }
  224. }
  225. /// Sends a sign in with email link to provided email address.
  226. ///
  227. /// The publisher will emit events on the **main** thread.
  228. ///
  229. /// - Parameters:
  230. /// - email: The email address of the user.
  231. /// - actionCodeSettings: An `ActionCodeSettings` object containing settings related to
  232. /// handling action codes.
  233. /// - Returns: A publisher that emits whether the call was successful or not. The publisher will
  234. /// emit on the *main* thread.
  235. @available(watchOS, unavailable)
  236. @discardableResult
  237. func sendSignInLink(toEmail email: String,
  238. actionCodeSettings: ActionCodeSettings) -> Future<Void, Error> {
  239. Future<Void, Error> { promise in
  240. self.sendSignInLink(toEmail: email, actionCodeSettings: actionCodeSettings) { error in
  241. if let error = error {
  242. promise(.failure(error))
  243. } else {
  244. promise(.success(()))
  245. }
  246. }
  247. }
  248. }
  249. // MARK: - Email-based Authentication Helpers
  250. /// Fetches the list of all sign-in methods previously used for the provided email address.
  251. ///
  252. /// The publisher will emit events on the **main** thread.
  253. ///
  254. /// - Parameter email: The email address for which to obtain a list of sign-in methods.
  255. /// - Returns: A publisher that emits a list of sign-in methods for the specified email
  256. /// address, or an error if one occurred. The publisher will emit on the *main* thread.
  257. /// - Remark: Possible error codes:
  258. /// - `AuthErrorCodeInvalidEmail` - Indicates the email address is malformed.
  259. ///
  260. /// See `AuthErrors` for a list of error codes that are common to all API methods
  261. func fetchSignInMethods(forEmail email: String) -> Future<[String], Error> {
  262. Future<[String], Error> { promise in
  263. self.fetchSignInMethods(forEmail: email) { signInMethods, error in
  264. if let error = error {
  265. promise(.failure(error))
  266. } else if let signInMethods = signInMethods {
  267. promise(.success(signInMethods))
  268. }
  269. }
  270. }
  271. }
  272. // MARK: - Password Reset
  273. /// Resets the password given a code sent to the user outside of the app and a new password for
  274. /// the user.
  275. ///
  276. /// The publisher will emit events on the **main** thread.
  277. ///
  278. /// - Parameters:
  279. /// - code: Out-of-band (OOB) code given to the user outside of the app.
  280. /// - newPassword: The new password.
  281. /// - Returns: A publisher that emits whether the call was successful or not. The publisher will
  282. /// emit on the *main* thread.
  283. /// - Remark: Possible error codes:
  284. /// - `AuthErrorCodeWeakPassword` - Indicates an attempt to set a password that is considered
  285. /// too weak.
  286. /// - `AuthErrorCodeOperationNotAllowed` - Indicates the admin disabled sign in with the
  287. /// specified identity provider.
  288. /// - `AuthErrorCodeExpiredActionCode` - Indicates the OOB code is expired.
  289. /// - `AuthErrorCodeInvalidActionCode` - Indicates the OOB code is invalid.
  290. ///
  291. /// See `AuthErrors` for a list of error codes that are common to all API methods
  292. @discardableResult
  293. func confirmPasswordReset(withCode code: String,
  294. newPassword: String) -> Future<Void, Error> {
  295. Future<Void, Error> { promise in
  296. self.confirmPasswordReset(withCode: code, newPassword: newPassword) { error in
  297. if let error = error {
  298. promise(.failure(error))
  299. } else {
  300. promise(.success(()))
  301. }
  302. }
  303. }
  304. }
  305. /// Checks the validity of a verify password reset code.
  306. ///
  307. /// The publisher will emit events on the **main** thread.
  308. ///
  309. /// - Parameter code: The password reset code to be verified.
  310. /// - Returns: A publisher that emits an error if the code could not be verified. If the code
  311. /// could be
  312. /// verified, the publisher will emit the email address of the account the code was issued
  313. /// for.
  314. /// The publisher will emit on the *main* thread.
  315. @discardableResult
  316. func verifyPasswordResetCode(_ code: String) -> Future<String, Error> {
  317. Future<String, Error> { promise in
  318. self.verifyPasswordResetCode(code) { email, error in
  319. if let error = error {
  320. promise(.failure(error))
  321. } else if let email = email {
  322. promise(.success(email))
  323. }
  324. }
  325. }
  326. }
  327. /// Checks the validity of an out of band code.
  328. ///
  329. /// The publisher will emit events on the **main** thread.
  330. ///
  331. /// - Parameter code: The out of band code to check validity.
  332. /// - Returns: A publisher that emits the email address of the account the code was issued for
  333. /// or an error if
  334. /// the code could not be verified. The publisher will emit on the *main* thread.
  335. @discardableResult
  336. func checkActionCode(code: String) -> Future<ActionCodeInfo, Error> {
  337. Future<ActionCodeInfo, Error> { promise in
  338. self.checkActionCode(code) { actionCodeInfo, error in
  339. if let error = error {
  340. promise(.failure(error))
  341. } else if let actionCodeInfo = actionCodeInfo {
  342. promise(.success(actionCodeInfo))
  343. }
  344. }
  345. }
  346. }
  347. /// Applies out of band code.
  348. ///
  349. /// The publisher will emit events on the **main** thread.
  350. ///
  351. /// - Parameter code: The out-of-band (OOB) code to be applied.
  352. /// - Returns: A publisher that emits an error if the code could not be applied. The publisher
  353. /// will emit on the *main* thread.
  354. /// - Remark: This method will not work for out-of-band codes which require an additional
  355. /// parameter,
  356. /// such as password reset codes.
  357. @discardableResult
  358. func applyActionCode(code: String) -> Future<Void, Error> {
  359. Future<Void, Error> { promise in
  360. self.applyActionCode(code) { error in
  361. if let error = error {
  362. promise(.failure(error))
  363. } else {
  364. promise(.success(()))
  365. }
  366. }
  367. }
  368. }
  369. /// Initiates a password reset for the given email address.
  370. ///
  371. /// The publisher will emit events on the **main** thread.
  372. ///
  373. /// - Parameter email: The email address of the user.
  374. /// - Returns: A publisher that emits whether the call was successful or not. The publisher will
  375. /// emit on the *main* thread.
  376. /// - Remark: Possible error codes:
  377. /// - `AuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was sent in
  378. /// the request.
  379. /// - `AuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in the console
  380. /// for this action.
  381. /// - `AuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for sending
  382. /// update email.
  383. ///
  384. /// See `AuthErrors` for a list of error codes that are common to all API methods
  385. @discardableResult
  386. func sendPasswordReset(withEmail email: String) -> Future<Void, Error> {
  387. Future<Void, Error> { promise in
  388. self.sendPasswordReset(withEmail: email) { error in
  389. if let error = error {
  390. promise(.failure(error))
  391. } else {
  392. promise(.success(()))
  393. }
  394. }
  395. }
  396. }
  397. /// Initiates a password reset for the given email address and `ActionCodeSettings`.
  398. ///
  399. /// The publisher will emit events on the **main** thread.
  400. ///
  401. /// - Parameter email: The email address of the user.
  402. /// - Parameter actionCodeSettings: An `ActionCodeSettings` object containing settings related
  403. /// to
  404. /// handling action codes.
  405. /// - Returns: A publisher that emits whether the call was successful or not. The publisher will
  406. /// emit on the *main* thread.
  407. /// - Remark: Possible error codes:
  408. /// - `AuthErrorCodeInvalidRecipientEmail` - Indicates an invalid recipient email was sent in
  409. /// the request.
  410. /// - `AuthErrorCodeInvalidSender` - Indicates an invalid sender email is set in the console
  411. /// for this action.
  412. /// - `AuthErrorCodeInvalidMessagePayload` - Indicates an invalid email template for sending
  413. /// update email.
  414. /// - `AuthErrorCodeMissingIosBundleID` - Indicates that the iOS bundle ID is missing
  415. /// when `handleCodeInApp` is set to YES.
  416. /// - `AuthErrorCodeMissingAndroidPackageName` - Indicates that the android package name is
  417. /// missing
  418. /// when the `androidInstallApp` flag is set to true.
  419. /// - `AuthErrorCodeUnauthorizedDomain` - Indicates that the domain specified in the continue
  420. /// URL is not whitelisted
  421. /// in the Firebase console.
  422. /// - `AuthErrorCodeInvalidContinueURI` - Indicates that the domain specified in the continue
  423. /// URI is not valid.
  424. ///
  425. /// See `AuthErrors` for a list of error codes that are common to all API methods
  426. @discardableResult
  427. func sendPasswordReset(withEmail email: String,
  428. actionCodeSettings: ActionCodeSettings) -> Future<Void, Error> {
  429. Future<Void, Error> { promise in
  430. self.sendPasswordReset(withEmail: email, actionCodeSettings: actionCodeSettings) { error in
  431. if let error = error {
  432. promise(.failure(error))
  433. } else {
  434. promise(.success(()))
  435. }
  436. }
  437. }
  438. }
  439. // MARK: - Other Authentication providers
  440. #if os(iOS) || targetEnvironment(macCatalyst)
  441. /// Signs in using the provided auth provider instance.
  442. ///
  443. /// The publisher will emit events on the **main** thread.
  444. ///
  445. /// - Parameters:
  446. /// - provider: An instance of an auth provider used to initiate the sign-in flow.
  447. /// - uiDelegate: Optionally, an instance of a class conforming to the `AuthUIDelegate`
  448. /// protocol. This is used for presenting the web context. If `nil`, a default
  449. /// `AuthUIDelegate`
  450. /// will be used.
  451. /// - Returns: A publisher that emits an `AuthDataResult` when the sign-in flow completed
  452. /// successfully, or an error otherwise. The publisher will emit on the *main* thread.
  453. /// - Remark: Possible error codes:
  454. /// - `AuthErrorCodeOperationNotAllowed` - Indicates that email and password accounts are
  455. /// not enabled.
  456. /// Enable them in the Auth section of the Firebase console.
  457. /// - `AuthErrorCodeUserDisabled` - Indicates the user's account is disabled.
  458. /// - `AuthErrorCodeWebNetworkRequestFailed` - Indicates that a network request within a
  459. /// `SFSafariViewController` or `WKWebView` failed.
  460. /// - `AuthErrorCodeWebInternalError` - Indicates that an internal error occurred within a
  461. /// `SFSafariViewController` or `WKWebView`.`
  462. /// - `AuthErrorCodeWebSignInUserInteractionFailure` - Indicates a general failure during a
  463. /// web sign-in flow.`
  464. /// - `AuthErrorCodeWebContextAlreadyPresented` - Indicates that an attempt was made to
  465. /// present a new web
  466. /// context while one was already being presented.`
  467. /// - `AuthErrorCodeWebContextCancelled` - Indicates that the URL presentation was cancelled
  468. /// prematurely
  469. /// by the user.`
  470. /// - `AuthErrorCodeAccountExistsWithDifferentCredential` - Indicates the email asserted by
  471. /// the credential
  472. /// (e.g. the email in a Facebook access token) is already in use by an existing account
  473. /// that cannot be
  474. /// authenticated with this sign-in method. Call `fetchProvidersForEmail` for this user’s
  475. /// email and then
  476. /// prompt them to sign in with any of the sign-in providers returned. This error will
  477. /// only be thrown if
  478. /// the "One account per email address" setting is enabled in the Firebase console, under
  479. /// Auth settings.
  480. ///
  481. /// See `AuthErrors` for a list of error codes that are common to all API methods
  482. @discardableResult
  483. func signIn(with provider: FederatedAuthProvider,
  484. uiDelegate: AuthUIDelegate?) -> Future<AuthDataResult, Error> {
  485. Future<AuthDataResult, Error> { promise in
  486. self.signIn(with: provider, uiDelegate: uiDelegate) { authDataResult, error in
  487. if let error = error {
  488. promise(.failure(error))
  489. } else if let authDataResult = authDataResult {
  490. promise(.success(authDataResult))
  491. }
  492. }
  493. }
  494. }
  495. #endif // os(iOS) || targetEnvironment(macCatalyst)
  496. /// Asynchronously signs in to Firebase with the given Auth token.
  497. ///
  498. /// The publisher will emit events on the **main** thread.
  499. ///
  500. /// - Parameter token: A self-signed custom auth token.
  501. /// - Returns: A publisher that emits an `AuthDataResult` when the sign-in flow completed
  502. /// successfully, or an error otherwise. The publisher will emit on the *main* thread.
  503. /// - Remark: Possible error codes:
  504. /// - `AuthErrorCodeInvalidCustomToken` - Indicates a validation error with the custom token.
  505. /// - `AuthErrorCodeUserDisabled` - Indicates the user's account is disabled.
  506. /// - `AuthErrorCodeCustomTokenMismatch` - Indicates the service account and the API key
  507. /// belong to different projects.
  508. ///
  509. /// See `AuthErrors` for a list of error codes that are common to all API methods
  510. @discardableResult
  511. func signIn(withCustomToken token: String) -> Future<AuthDataResult, Error> {
  512. Future<AuthDataResult, Error> { promise in
  513. self.signIn(withCustomToken: token) { authDataResult, error in
  514. if let error = error {
  515. promise(.failure(error))
  516. } else if let authDataResult = authDataResult {
  517. promise(.success(authDataResult))
  518. }
  519. }
  520. }
  521. }
  522. /// Asynchronously signs in to Firebase with the given 3rd-party credentials (e.g. a Facebook
  523. /// login Access Token, a Google ID Token/Access Token pair, etc.) and returns additional
  524. /// identity provider data.
  525. ///
  526. /// The publisher will emit events on the **main** thread.
  527. ///
  528. /// - Parameter credential: The credential supplied by the IdP.
  529. /// - Returns: A publisher that emits an `AuthDataResult` when the sign-in flow completed
  530. /// successfully, or an error otherwise. The publisher will emit on the *main* thread.
  531. /// - Remark: Possible error codes:
  532. /// - `FIRAuthErrorCodeInvalidCredential` - Indicates the supplied credential is invalid.
  533. /// This could happen if it has expired or it is malformed.
  534. /// - `FIRAuthErrorCodeOperationNotAllowed` - Indicates that accounts
  535. /// with the identity provider represented by the credential are not enabled.
  536. /// Enable them in the Auth section of the Firebase console.
  537. /// - `FIRAuthErrorCodeAccountExistsWithDifferentCredential` - Indicates the email asserted
  538. /// by the credential (e.g. the email in a Facebook access token) is already in use by an
  539. /// existing account, that cannot be authenticated with this sign-in method. Call
  540. /// fetchProvidersForEmail for this user’s email and then prompt them to sign in with any of
  541. /// the sign-in providers returned. This error will only be thrown if the "One account per
  542. /// email address" setting is enabled in the Firebase console, under Auth settings.
  543. /// - `FIRAuthErrorCodeUserDisabled` - Indicates the user's account is disabled.
  544. /// - `FIRAuthErrorCodeWrongPassword` - Indicates the user attempted sign in with an
  545. /// incorrect password, if credential is of the type EmailPasswordAuthCredential.
  546. /// - `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is malformed.
  547. /// - `FIRAuthErrorCodeMissingVerificationID` - Indicates that the phone auth credential was
  548. /// created with an empty verification ID.
  549. /// - `FIRAuthErrorCodeMissingVerificationCode` - Indicates that the phone auth credential
  550. /// was created with an empty verification code.
  551. /// - `FIRAuthErrorCodeInvalidVerificationCode` - Indicates that the phone auth credential
  552. /// was created with an invalid verification Code.
  553. /// - `FIRAuthErrorCodeInvalidVerificationID` - Indicates that the phone auth credential was
  554. /// created with an invalid verification ID.
  555. /// - `FIRAuthErrorCodeSessionExpired` - Indicates that the SMS code has expired.
  556. ///
  557. /// See `AuthErrors` for a list of error codes that are common to all API methods
  558. @discardableResult
  559. func signIn(with credential: AuthCredential) -> Future<AuthDataResult, Error> {
  560. Future<AuthDataResult, Error> { promise in
  561. self.signIn(with: credential) { authDataResult, error in
  562. if let error = error {
  563. promise(.failure(error))
  564. } else if let authDataResult = authDataResult {
  565. promise(.success(authDataResult))
  566. }
  567. }
  568. }
  569. }
  570. }
  571. #endif // canImport(Combine) && swift(>=5.0)