I'm trying and failing badly to implement the cool Firebase email link login feature. I successfully setup sending an email link. However, I can't get the email link to open up the app. It just opens up the preview page like it can't open the app.
I've tested the dynamic link I setup and I can get it to open up the app in a device. I just can't get the email link to do the same.
Code in my app:
func sendFirebaseEmailLink() {
let actionCodeSettings = ActionCodeSettings.init()
// userEmail comes from a textField
let email = userEmail
actionCodeSettings.url = URL.init(string: String(format: "https://<myappname>.firebaseapp.com/?email=%#", email))
// The sign-in operation has to always be completed in the app.
actionCodeSettings.handleCodeInApp = true
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
Auth.auth().sendSignInLink(toEmail: email,
actionCodeSettings: actionCodeSettings) { error in
if let error = error {
print(error.localizedDescription)
return
}
else {
UserDefaults.standard.set(email, forKey: "Email")
print("email sent to user")
}
}
}
When I say I've successfully gotten my dynamic link to open the app what I mean is when I follow the link I created (mylinkname.page.link/emaillogin) on a device that has the app installed, it opens the app. Because of that and [this helpful Firebase video][1] on setting up a dynamic link it seems like I've got those details correct and the issue is with the code, but I'm new to this so I'm not sure.
I've spend few days going around in circles to figure this out, and trying to parse the dense Firebase documentation, so any ideas are greatly appreciated.
I finally figured it out. The code was fine. It was an issue related to the dynamic link. I had a couple links setup in Firebase because I had to create a new Bundle ID at one point. When I deleted out the old one in Firebase the email link started working.
It shows up in my app association site like this, and oddly still does even though I deleted out the old link, but at least it works now!
{"applinks":{"apps":[],"details":[{"appID":"TEAMID.com.OLDBUNDLEIDENTIFIER.APPNAME","paths":["NOT //*","/*"]},{"appID":"TEAMID.com.NEWBUNDLEIDENTIFIER.APPNAME","paths":["NOT //","/"]}]}}
UPDATE: My full code to implement passwordless email login is below. It was painful for me to piece together using the documentation so hopefully this saves you the trouble.
Key steps assuming you understand the basics of Firebase Setup.
1) Setup a Dynamic Link Using the Firebase Video tutorial.
2) Code in View Controller:
var userEmail: String?
var link: String?
func sendFirebaseEmailLink() {
let actionCodeSettings = ActionCodeSettings.init()
let email = userEmail
actionCodeSettings.url = URL.init(string: String(format: "https://<myappname>.page.link/emaillogin/?email=%#", email!))
// The sign-in operation has to always be completed in the app.
actionCodeSettings.handleCodeInApp = true
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
Auth.auth().sendSignInLink(toEmail: email!,
actionCodeSettings: actionCodeSettings) { error in
if let error = error {
print(error.localizedDescription)
return
}
else {
UserDefaults.standard.set(email, forKey: "Email")
print("email sent to user")
}
// TODO: Notify user to check email and click the link.
}
}
// Sign in user after they clicked email link called from AppDelegate
#objc func signInUserAfterEmailLinkClick() {
// Get link url string from the dynamic link captured in AppDelegate.
if let link = UserDefaults.standard.value(forKey: "Link") as? String {
self.link = link
}
// Sign user in with the link and email.
Auth.auth().signIn(withEmail: userEmail!, link: link!) { (result, error) in
if error == nil && result != nil {
if (Auth.auth().currentUser?.isEmailVerified)! {
print("User verified with passwordless email")
// TODO: Do something after user verified like present a new View Controller
}
else {
print("User NOT verified by passwordless email")
}
}
else {
print("Error with passwordless email verfification: \(error?.localizedDescription ?? "Strangely, no error avaialble.")")
}
}
}
3) Code in AppDelegate
// For Passwordless Email Login to Handle Dynamic Link after User Clicks Email Link
func application(_ application: UIApplication, continue userActivity: NSUserActivity,
restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
if let incomingURL = userActivity.webpageURL {
print("Incoming URL is \(incomingURL)")
// Parse incoming
let linkHandled = DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) { (dynamicLink, error) in
guard error == nil else {
print("Found an error: \(error!.localizedDescription)")
return
}
if let dynamicLink = dynamicLink {
self.handleIncomingDynamicLink(dynamicLink)
}
}
if linkHandled {
return true
}
else {
// Maybe do other things with dynamic links in future?
return false
}
}
return false
}
// Handles the link and saves it to userDefaults to assist with login.
func handleIncomingDynamicLink(_ dynamicLink: DynamicLink) {
guard let url = dynamicLink.url else {
print("My dynamic link object has no url")
return
}
print("Incoming link parameter is \(url.absoluteString)")
let link = url.absoluteString
if Auth.auth().isSignIn(withEmailLink: link) {
// Save link to userDefaults to help finalize login.
UserDefaults.standard.set(link, forKey: "Link")
// Send notification to ViewController to push the First Time Login VC
NotificationCenter.default.post(
name: Notification.Name("SuccessfulPasswordlessEmailNotification"), object: nil, userInfo: nil)
}
}
For anyone using SwiftUI with AppDelegate and SceneDelegate files instead of UIKit, here's what I've done:
Create a function to send a link to the user's email
func sendSignLink(email: String) async throws {
do {
let actionCodeSettings = ActionCodeSettings()
actionCodeSettings.url = URL(string: "*enter your Firebase Dynamic link here*")
actionCodeSettings.handleCodeInApp = true
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
try await Auth.auth().sendSignInLink(toEmail: email, actionCodeSettings: actionCodeSettings)
UserDefaults.standard.set(email, forKey: "email")
}
catch {
throw error
}
}
In the SceneDelegate file, import FirebaseDynamicLinks and add the below code
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
if let incomingURL = userActivity.webpageURL {
print("\n \nIncoming URL is \(incomingURL)")
_ = DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL) { (dynamicLink, error) in
guard error == nil else {
print("\n \nError with handling incoming URL: \(error!.localizedDescription)")
return
}
if let dynamicLink = dynamicLink {
guard let url = dynamicLink.url else {
print("\n \nDynamic link object has no url")
return
}
print("\n \nIncoming link parameter is \(url.absoluteString)")
let link = url.absoluteString
if Auth.auth().isSignIn(withEmailLink: link) {
// Send notification to trigger the rest of the sign in sequence
NotificationCenter.default.post(name: Notification.Name("Success"), object: nil, userInfo: ["link": link])
} else {
// Send error notification
NotificationCenter.default.post(name: Notification.Name("Error"), object: nil, userInfo: nil)
}
}
}
}
}
Create a function to handle the sign in after the user has clicked on the link in their email
func signInWithEmail(link: String) async throws {
do {
let email = UserDefaults.standard.value(forKey: "email")
try await Auth.auth().signIn(withEmail: email, link: link)
}
catch {
throw error
}
}
In a relevant view, handle the notifications which get posted
struct MyView: View {
var body: some View {
VStack {
Text("View")
}
.onReceive(NotificationCenter.default.publisher(for: Notification.Name("Success"))) { notificationInfo in
if let userInfo = notificationInfo.userInfo {
if let link = userInfo["link"] as? String {
Task.init {
do {
try await signInWithEmail(link: link)
} catch {
print(error)
}
}
}
}
}
.onReceive(NotificationCenter.default.publisher(for: Notification.Name("Error"))) { _ in
//do something with error
}
}
}
Related
I want user to login once and not have to reenter their login info everytime they open app unless they logout in the last session.
Login screen is currently displayed everytime the app is open. This is my rootview
struct AppRootView: View {
var body: some View {
AnyView {
// check if user has already logged in here and then route them accordingly
if auth.token != nil {
homeMainView()
} else {
LoginController()
}
}
}
}
currently this is what I use to login users
#objc func signUp() {
setLoading(true);
app.usernamePasswordProviderClient().registerEmail(username!, password: password!, completion: {[weak self](error) in
// Completion handlers are not necessarily called on the UI thread.
// This call to DispatchQueue.main.sync ensures that any changes to the UI,
// namely disabling the loading indicator and navigating to the next page,
// are handled on the UI thread:
DispatchQueue.main.sync {
self!.setLoading(false);
guard error == nil else {
print("Signup failed: \(error!)")
self!.errorLabel.text = "Signup failed: \(error!.localizedDescription)"
return
}
print("Signup successful!")
// Registering just registers. Now we need to sign in, but we can reuse the existing username and password.
self!.errorLabel.text = "Signup successful! Signing in..."
self!.signIn()
}
})
}
#objc func signIn() {
print("Log in as user: \(username!)");
setLoading(true);
app.login(withCredential: AppCredentials(username: username!, password: password!)) { [weak self](maybeUser, error) in
DispatchQueue.main.sync {
self!.setLoading(false);
guard error == nil else {
// Auth error: user already exists? Try logging in as that user.
print("Login failed: \(error!)");
self!.errorLabel.text = "Login failed: \(error!.localizedDescription)"
return
}
guard let user = maybeUser else {
fatalError("Invalid user object?")
}
print("Login succeeded!");
//
let hostingController = UIHostingController(rootView: ContentView())
self?.navigationController?.pushViewController(hostingController, animated: true)
}
how could I implement one time login so that users do have to login each time they open the app?
A correctly configured and initialized RealmApp class will persist the session information for you between app restarts, you can check for an existing session using the .currentUser() method from this class. So in your case something like:
if app.currentUser() != nil {
homeMainView()
} else {
LoginController()
}
While using Realm to persist login is a good idea, but I would highly
advice against using it for managing user authentication credentials such
as passwords. A better approach if you want to save sensitive information is
using KeyChain just like what Apple and password manager apps do. With a light
weight keyChain wrapper library such as SwiftKeychainWrapper You can easily
save your login credentials in the most secure way.
Here is a sample using a keyChain wrapper linked above.
With simple modification you can use this helper class to manage your sign in credentials anywhere in your app.
import SwiftKeychainWrapper
class KeyChainService {
// Make a singleton
static let shared = KeyChainService()
// Strings which will be used to map data in keychain
private let passwordKey = "passwordKey"
private let emailKey = "emailKey"
private let signInTokenKey = "signInTokenKey"
// Saving sign in info to keyChain
func saveUserSignInInformation(
email: String,
password: String,
token: String
onError: #escaping() -> Void,
onSuccess: #escaping() -> Void
) {
DispatchQueue.global(qos: .default).async {
let passwordIsSaved: Bool = KeychainWrapper.standard.set(password, forKey: self.passwordKey)
let emailIsSaved: Bool = KeychainWrapper.standard.set(email, forKey: self.emailKey)
let tokenIsSaved: Bool = KeychainWrapper.standard.set(token, forKey: self.signInTokenKey)
DispatchQueue.main.async {
// Verify that everything is saved as expected.
if passwordIsSaved && emailIsSaved && tokenIsSaved {
onSuccess()
}else {
onError()
}
}
}
}
// Retrieve signIn information for auto login
func retrieveSignInInfo(onError: #escaping() -> Void, onSuccess: #escaping(UserModel) -> Void) {
DispatchQueue.main.async {
let retrievedPassword: String? = KeychainWrapper.standard.string(forKey: self.passwordKey)
let retrievedEmail: String? = KeychainWrapper.standard.string(forKey: self.emailKey)
let retrievedToken: String? = KeychainWrapper.standard.string(forKey: self.signInTokenKey)
if let password = retrievedPassword,
let email = retrievedEmail,
let token = retrievedToken {
// Assuming that you have a custom user model named "UserModel"
let user = UserModel(email: email, password: password,token: token)
// Here is your user info which you can use to verify with server if needed and auto login user.
onSuccess(user)
}else {
onError()
}
}
}
}
I have a really weird bug right now. Inside my app the user is able to login with Email/Facebook/Google. This is how the bug occurs:
When I log in via Email and log out again and then use one of the Social-Logins, it logs me into the email account that I used before??? How and why is that happening? It makes absolut no sense for me.
This is for example my facebookLogin- method (google-method works pretty much the same way):
//MARK: Facebook Login
#objc func facebookButtonTapped(){
// disable button tap
self.facebookButton.isEnabled = false
let accessToken = AccessToken.current
LoginManager().logIn(permissions: ["email", "public_profile"], from: self) { (result, error) in
if error != nil {
// some FB error
Utilities.showErrorPopUp(labelContent: "Fehler beim Facebook-Login", description: error!.localizedDescription)
return
}else if result?.isCancelled == true {
// enable button tap
self.facebookButton.isEnabled = true
}else {
// successfull FB-Login
GraphRequest(graphPath: "/me", parameters: ["fields": "id, email, name"]).start { (connection, result, error) in
if error != nil {
// some FB error
Utilities.showErrorPopUp(labelContent: "Fehler beim Facebook-Login", description: error!.localizedDescription)
}else {
print(result!)
// check if user has account
guard let Info = result as? [String: Any] else { return }
let email = Info["email"] as? String
print(email!)
Auth.auth().fetchSignInMethods(forEmail: email!) { (methods, error) in
if error != nil {
// show error popUp
Utilities.showErrorPopUp(labelContent: "Fehler", description: error!.localizedDescription)
} else {
// no error -> check email adress
// enable button tap
self.facebookButton.isEnabled = true
// Email ist noch nicht registriert -> sign up
if methods == nil {
let usernameVC = self.storyboard?.instantiateViewController(withIdentifier: "UsernameVC") as! UserNameVC
usernameVC.accessToken = accessToken
usernameVC.signInOption = "facebook"
self.navigationController?.pushViewController(usernameVC, animated: true)
}
// Email is registered -> login
else {
// set user status to logged-in
UserDefaults.standard.setIsLoggedIn(value: true)
UserDefaults.standard.synchronize()
// enable button tap
self.facebookButton.isEnabled = true
// transition to Home-ViewController
self.transitionToHome()
}
}
}
}
}
}
}
}
I also tested and printed the Auth.auth().currentUser!.uid inside my HomeViewController and it is actually logging into the previous used Email-Account! Super weird...
If anyone can bring some light into this and help me out I am more than grateful!
If there is anything unclear and you need more info just let me know.
Solved the issue.. The problem was that I never actually logged the in. I just checked wether or not the user has an account. I missed to call Auth.auth().signIn
I have a requirement to open a tweet in my app, if the user has twitter installed, open in Twitter, otherwise present a webview and render the tweet.
I am able to achieve this essentially with the below. It works and I am happy with it.
However when initially prompted to open in Twitter, should the user click cancel, I'd like to present the webview instead. Currently however if the user clicks cancel, nothing happens and they need to tap the tweet item in there feed again.
Is it possible to have a fallback should the user click cancel in the message?
func didSelectItemInFeed(_ selected: FeedItem) {
switch selected.item.type {
case .companyNews:
....
case .tweet:
guard
let username = selected.item.tweet?.displayName,
let appURL = URL(string: "twitter://status?id=\(selected.item.externalId)"),
let webURL = URL(string: "https://twitter.com/\(username)/status/\(selected.item.externalId)")
else { return }
let application = UIApplication.shared
if application.canOpenURL(appURL as URL) {
application.open(appURL as URL)
} else {
presentWebView(webURL)
}
default:
break
}
}
Complete your function with: application.open(appURL as URL, completionHandler: {isSuccess in})()
func didSelectItemInFeed(_ selected: FeedItem) {
switch selected.item.type {
case .companyNews:
....
case .tweet:
guard
let username = selected.item.tweet?.displayName,
let appURL = URL(string: "twitter://status?id=\(selected.item.externalId)"),
let webURL = URL(string: "https://twitter.com/\(username)/status/\(selected.item.externalId)")
else { return }
let application = UIApplication.shared
if application.canOpenURL(appURL as URL) {
application.open(appURL as URL, completionHandler: { isSuccess in
// print here does your handler open/close : check 'isSuccess'
})()
} else {
presentWebView(webURL)
}
default:
break
}
}
application.open has an optional completion handler:
application.open(appURL) { (success) in
print("Success \(success)")
}
You should check the success status.
I am using phone authentication using cloud firestore. In firestore db, I am storing user phone number and uid. Here is the code which, I have tried for mobile number login:
#IBAction func signUp(_ sender: Any) {
// dismiss keyboard
view.endEditing(true)
if sendOTP == false {
let mobileNumber = "+91" + phoneNumberTextField.text!
self.Userdefaults.set(mobileNumber, forKey: "mobileNumber")
print("mobileNumber::::\(mobileNumber)")
sendOTPCode()
sendOTP = true
} else {
let codestring = OTPCodeTextField.text
if codestring?.count == 6 {
loginusingOTP(OTPtext: codestring!)
} else {
print("Enter 6 digit code")
}
}
func sendOTPCode() {
let mymobilenumber = Userdefaults.string(forKey: "mobileNumber")
PhoneAuthProvider.provider().verifyPhoneNumber(mymobilenumber!) { (verificationID, error) in
self.Userdefaults.set(verificationID, forKey: "authVerificationID")
if error != nil
{
print ("insde SendCode, there is error")
print("error: \(String(describing: error?.localizedDescription))")
} else {
print ("code sent")
self.phoneNumberTextField.allowsEditingTextAttributes = false
}
}
}
func loginusingOTP(OTPtext: String) {
let db = Firestore.firestore()
let verificationID = self.Userdefaults.string(forKey: "authVerificationID")
let credential: PhoneAuthCredential = PhoneAuthProvider.provider().credential(withVerificationID: verificationID!,
verificationCode: OTPtext)
Auth.auth().signIn(with: credential)
{
(user, error) in
if error != nil
{
print("error: \(String(describing: error?.localizedDescription))")
}
else if user != nil
{
print("Phone number: \(String(describing: user?.phoneNumber))")
let userInfo = user?.providerData[0]
print("Provider ID: \(String(describing: userInfo?.providerID))")
var _: DocumentReference? = nil
print("currentUser:::\(String(describing: currentUser))")
db.collection("users").document(currentUser!).setData([
"User_Phone_number": user?.phoneNumber as Any,
"uid": currentUser as Any
]) { err in
if let err = err {
print("Error writing document: \(err)")
} else {
print("Document successfully written!")
if PrefsManager.sharedinstance.isFirstTime == false{
let when = DispatchTime.now() + 0
DispatchQueue.main.asyncAfter(deadline: when) {
self.performSegue(withIdentifier: "signUpToTabBar", sender: nil)
}
}else{
let when = DispatchTime.now() + 0
DispatchQueue.main.asyncAfter(deadline: when) {
let storyboard = UIStoryboard(name: "Start", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "onboardvc")
self.present(initialViewController, animated: true, completion: nil)
}
}
}
}
} else {
print("error::::::")
}
}
}
User login flow - First user enter phone number and then taps on send otp then user enters otp code, logged in successfully. Since user login first time, user needs to fill user detail page and then goes to home page. If its already logged in user, after successful of login user will redirected to home screen not the user detail page.
My question is now user is login each and every time to get inside of the app, I want user to login automatically without login each and every time unless user logout. How to check already logged in user UID or phone in cloud firestore for user exist or new user.
Any help much appreciated pls...
Let me give you brief scenario.
SwiftyUserDefaults is the best library to store UserDefaults throughout the app.
Create one extension like this,
extension DefaultsKeys {
static let username = DefaultsKey<String?>("username")
static let phoneNo = DefaultsKey<String?>("phoneNo")
static let islogin = DefaultsKey<Bool?>("islogin")
}
After successful login, you can set the values of the above DefaultKeys like below, first import SwiftyUserDefaults,
Defaults[.username] = Your_User_Name
Defaults[.phoneno] = Your_Phone_No
Defaults[.islogin] = true
Now on your first LoginViewController, in viewDidLoad() method, Please check following,
if Defaults[.islogin] == true {
//Go to Home with animation false
}
Here you go, let me know in case of any queries.
FYI. This is just the scenario, actual may be different depending on your final requirement. This answer may help you.
For Firebase (and it looks like FireStore). Once the User is Authenticated on the device, they will automatically be "logged in" to Firebase/Firestore next sessions unless there is a specific SignOut (Auth.auth().signOut()) or unless there is a super long delay (not sure how long, maybe a month).
To check to see if the user is already logged in.
On Start Up (didFinishLaunchingWithOptions) set up an Auth Listener and it will fire once and return the current Auth Status.
func addUserListener() {
listenHandler = Auth.auth().addStateDidChangeListener { (auth, user) in
if user == nil {
// We are Logged Out of Firebase.
// Move to Login Screen
} else {
// we are Logged In to Firebase.
// Move to Main Screen
}
}
You really need to use an Auth Listener for Login calls as if someone has two devices and logs out on one device, they will be logged out of firebase and the 2nd device will crash when you try a firebase call, because it still thinks its logged in.
Update your login credentials OR loggedIn flag to user Defaults
UserDefaults.standard.set("value", forKey: "username")
UserDefaults.standard.set("value", forKey: "password")
(NB: i recommended not to store password directly, you could store authentication token in Userdefaults, & if you want password to be stored, use keychain instead)
And redirect to corresponding page from AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var initialViewController: UIViewController?
let mainStoryboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
if let username = UserDefaults.standard.value(forKey: "username"), let password = UserDefaults.standard.value(forKey: "password") {
initialViewController = mainStoryboard.instantiateViewController(withIdentifier: "HomeVC")
} else {
initialViewController = mainStoryboard.instantiateViewController(withIdentifier: "LoginVC")
}
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
Currently I allow users to "Sign In with Facebook":
#objc func handleFBLogin() {
FBSDKLoginManager().logIn(withReadPermissions: ["email", "public_profile"], from: self) { (result, error) in
if error != nil {
print(error as Any)
return
}
self.handleFBAccessToken()
}
}
func handleFBAccessToken() {
let accessToken = FBSDKAccessToken.current()
guard let accessTokenString = accessToken?.tokenString else { return }
let credentials = FacebookAuthProvider.credential(withAccessToken: accessTokenString)
Auth.auth().signIn(with: credentials) { (user, error) in
if error != nil {
// I assume I handle the errors here
print(error as Any)
return
}
// successfully logged in user
self.instantiateTabVC()
}
FBSDKGraphRequest(graphPath: "/me", parameters: ["fields": "id, name, email"]).start { (connection, result, error) in
if error != nil {
print(error as Any)
}
}
}
I'd like to add it so that if they've already made an account via email/password, the two accounts will be automatically linked/merged (or vice versa). In "I assume I handle the errors here", I added
let providers = Auth.auth().fetchProviders(forEmail: AuthErrorUserInfoEmailKey)
// sign in with existing account
// call linkWithCredential:completion:
to fetch the email that already exists. I am basing this off of this and this (both similar questions). I understand that the premise is to
use fetchProvidersForEmail with that email which will lookup the provider IDs associated with that email. You then sign in the user with one of those providers. After you finish sign-in with the existing account, you call linkWithCredential:completion: with the original credential that caused the error to occur
However, I am new to Swift and extremely confused about how to go about that. Any sample code would be extremely beneficial. I've also tried reading the documentation but that hasn't helped either (as I probably have not learned to properly understand the documentation)
I hope that I am moving in the right direction to solve this problem, however, if you have any other suggestions, I'd be open to that. I appreciate any help
Try this Approach this will doesn't create a new user if exists.
func facebook() {
let loginManager: FBSDKLoginManager = FBSDKLoginManager()
loginManager.logIn(withReadPermissions: ["email"], from: self, handler: { result, error in
if let error = error {
self.showMessagePrompt(error.localizedDescription)
} else if result!.isCancelled {
print("FBLogin cancelled")
} else {
// [START headless_facebook_auth]
let credential = FacebookAuthProvider.credential(withAccessToken: FBSDKAccessToken.current().tokenString)
// [END headless_facebook_auth]
self.firebaseLogin(credential)
}
})
}
func firebaseLogin(_ credential: AuthCredential) {
if let user = Auth.auth().currentUser {
// [START link_credential]
user.link(with: credential) { _, error in
// [START_EXCLUDE]
if let error = error {
self.showMessagePrompt(error.localizedDescription)
return
}
// [END_EXCLUDE]
}
// [END link_credential]
} else {
// [START signin_credential]
Auth.auth().signIn(with: credential) { _, error in
// [START_EXCLUDE silent]
self.hideSpinner {
// [END_EXCLUDE]
if let error = error {
// [START_EXCLUDE]
self.showMessagePrompt(error.localizedDescription)
// [END_EXCLUDE]
return
}
// User is signed in
// [START_EXCLUDE]
// Merge prevUser and currentUser accounts and data
// ...
// [END_EXCLUDE]
}
}
// [END signin_credential]
}
}