I'm using Firebase Auth for my Swift iOS app. Google recommends using Firebase Auth UI as a "drop in" authentication system, but it only handles the initial login. I'm now working on allowing the user to make profile changes, such as email and password.
The documentation for making these changes mentions in several places that certain changes require the user to have logged in recently (see https://firebase.google.com/docs/auth/ios/manage-users#get_the_currently_signed-in_user):
Some security-sensitive actions—such as deleting an account, setting a primary email address, and changing a password—require that the user has recently signed in. If you perform one of these actions, and the user signed in too long ago, the action fails with the FIRAuthErrorCodeCredentialTooOld error.
First of all, there doesn't appear to be a FIRAuthErrorCodeCredentialTooOld
error anywhere in the API.
Second, the documentation suggests using reauthenticate(with:)
to solve this problem, with this code sample:
let user = FIRAuth.auth()?.currentUser
var credential: FIRAuthCredential
// Prompt the user to re-provide their sign-in credentials
user?.reauthenticate(with: credential) { error in
if let error = error {
// An error happened.
} else {
// User re-authenticated.
}
}
The problem is, because I used Firebase Auth UI, I have no custom UI for getting the user's credentials.
My current thinking is I could reauthenticate by presenting the same Firebase Auth UI used for logging in when this error occurs. However, I don't know if this is the sanctioned way to do this, or if it will work at all, or if it will continue to work in the future. I checked the Firebase Auth UI code base and there is no call to reauthenticate()
anywhere. The documentation makes a big deal of calling this method specifically in case of this error, so I'm confused.
If I need to build an entire UI to perform reauthentication, including multiple providers, what's the point of using Firebase Auth UI?
Firebase Authentication provides backend services, easy-to-use SDKs, and ready-made UI libraries to authenticate users to your app. It supports authentication using passwords, phone numbers, popular federated identity providers like Google, Facebook and Twitter, and more.
Firebase gives you complete control over authentication by allowing you to authenticate users or devices using secure JSON Web Tokens (JWTs). You generate these tokens on your server, pass them back to a client device, and then use them to authenticate via the signInWithCustomToken() method.
Firebase ID tokens are short lived and last for an hour; the refresh token can be used to retrieve new ID tokens. Refresh tokens expire only when one of the following occurs: The user is deleted. The user is disabled.
Regarding the error code, the documentation just needs updating. The error code is now called FIRAuthErrorCode.errorCodeRequiresRecentLogin
.
Now, as of the UI problem you're facing, why not just present a UIAlertController
with a text field that the users can use to enter their passwords for re-authentication? It's certainly much simpler (and user-friendlier) than creating an entire view controller.
Here's a pretty straightforward sample of how you can re-authenticate your users without going through so much trouble:
// initialize the UIAlertController for password confirmation
let alert = UIAlertController(title: "", message: "Please, enter your password:", preferredStyle: UIAlertControllerStyle.alert)
// add text field to the alert controller
alert.addTextField(configurationHandler: { (textField) in
textField.placeholder = "Password"
textField.autocapitalizationType = .none
textField.autocorrectionType = .no
textField.isSecureTextEntry = true
})
// delete button action
alert.addAction(UIAlertAction(title: "Delete account", style: UIAlertActionStyle.destructive, handler: {action in
// retrieve textfield
let txtFld = alert.textFields![0]
// init the credentials (assuming you're using email/password authentication
let credential = FIREmailPasswordAuthProvider.credential(withEmail: (FIRAuth.auth()?.currentUser?.email)!, password: txtFld.text!)
FIRAuth.auth()?.currentUser?.reauthenticate(with: credential, completion: { (error) in
if error != nil {
// handle error - incorrect password entered is a possibility
return
}
// reauthentication succeeded!
})
}))
// cancel reauthentication
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: {action in }))
// finally, present the alert controller
self.present(alert, animated: true, completion: nil)
Whenever you need to change the user's email or delete their account (password reset doesn't require a login at all), use the snippet above to just pop up an alert controller where they can re-enter their password.
EDIT: Please note that the code provided above force-unwraps the current user's email, so make sure you have a user logged-in at that stage or your app will crash.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With