"provideCredentialWithoutUserInteractionForIdentity:" is not working - ios

I have an app that autofills the password on iOS 12. Now I want to implement this function:
- (void)provideCredentialWithoutUserInteractionForIdentity:(ASPasswordCredentialIdentity *)credentialIdentity;
But I cant get it to work like it should.
AutoFill is enabled in settings and also enabled for my app.
I've read the documentation but this doens't help me. https://developer.apple.com/documentation/authenticationservices/ascredentialproviderviewcontroller/2977554-providecredentialwithoutuserinte?language=objc
I've tried calling this function from viewDidLoad, prepareCredentialListForServiceIdentifiers,.. but this is stupid and definitely won't work.
- (void)provideCredentialWithoutUserInteractionForIdentity:(ASPasswordCredentialIdentity *)credentialIdentity {
ASPasswordCredential *credential = [[ASPasswordCredential alloc] initWithUser:#"theUsername" password:#"thePassword"];
[self.extensionContext completeRequestWithSelectedCredential:credential completionHandler:nil];
}
The function should show the credentials above the keyboard, but this doesn't happen. It just shows the default "Passwords" button.

Make sure you have some ASPasswordCredentialIdentitys for your domain/url in ASCredentialIdentityStore. (These are records with some unique recordIdentifier, that doesn't hold password but hold data that can help you decide what password you should take from some secure storage of your choice.)
When you open a website, iOS looks up the ASCredentialIdentityStore, and shows a big button for quick login if there's a matching record. If you hit the button - this is only when provideCredentialWithoutUserInteraction callback is executed. Your task is to work with ASPasswordCredentialIdentity passed as an argument (it has recordIdentifier field) and find matching password for it (in your database/keychain/etc.) When you have password - you create ASPasswordCredential and pass it to self.extensionContext.completeRequest. Also make sure to call extensionContext.cancelRequest in case of any errors.
here's my example
override func provideCredentialWithoutUserInteraction(for credentialIdentity: ASPasswordCredentialIdentity) {
let databaseIsUnlocked = false
if (databaseIsUnlocked) {
// this function queries my custom keychain records by recordIdentifier (Generic Passwords) to find matching password
getItemForRecordId(identifier: credentialIdentity.recordIdentifier) { password, err in
guard password != nil else {
print("password was nil")
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code:ASExtensionError.userInteractionRequired.rawValue))
return;
}
let passwordCredential = ASPasswordCredential(user: credentialIdentity.user, password: password as! String);
self.extensionContext.completeRequest(withSelectedCredential: passwordCredential, completionHandler: nil);
};
} else {
self.extensionContext.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code:ASExtensionError.userInteractionRequired.rawValue))
}
}

Related

use of restorePreviousSignIn() in googleSign in iOS

Google migration doc here says that
// Old:
guard let signIn = GIDSignIn.sharedInstance() else { return }
if (signIn.hasAuthInKeychain()) {
signIn.signInSilently()
}
// New:
guard let signIn = GIDSignIn.sharedInstance() else { return }
if (signIn.hasPreviousSignIn()) {
signIn.restorePreviousSignIn()
// If you ever changed the client ID you use for Google Sign-in, or
// requested a different set of scopes, then also confirm that they
// have the values you expect before proceeding.
if (signIn.currentUser.authentication.clientID != YOUR_CLIENT_ID
// TODO: Implement hasYourRequiredScopes
|| !hasYourRequiredScopes(signIn.currentUser.grantedScopes)) {
signIn.signOut()
}
}
As I had tried with device user still get redirect to account.google.com and have to choose the account right? so what is use of restorePreviousSignIn(). How it benefit to user? Thanks in advance.
Do you set the GIDSignInDelegate (GIDSignIn.sharedInstance().delegate) before calling restorePreviousSignIn()?
As the documentation of restorePreviousSignIn() says:
The delegate will be called at the end of this process indicating success or failure. The current values of GIDSignIn's configuration properties will not impact the restored user.
Btw. I'm using the restorePreviousSignIn() without any trouble.
// Sorry for asking in answer, I don't have enough reputation to comment on you question.

Catch certain Firebase Error in iOS not working

Updated question
I am trying to manually check if the user is has to be reauthenticated or not. This is what I've come up with:
//MARK: updateEmail
static func updateEmail(email: String, finished: #escaping (_ done: Bool, _ hasToReauthenticate: Bool) -> Void) {
let currentUser = Auth.auth().currentUser
currentUser?.updateEmail(to: email) { err in
if err != nil {
if let errCode = AuthErrorCode(rawValue: err!._code) {
switch errCode {
case .userTokenExpired:
print("expired")
finished(true, true)
break
default:
Utilities.showErrorPopUp(labelContent: "Fehler", description: err!.localizedDescription)
finished(false, false)
}
}
} else {
finished(true, false)
}
}
}
But this is never going through the .userTokenExpired case even when it should.. What am I missing here ?
There is no API in Firebase Authentication that returns when the user has last authenticated, or whether that was recently. The only built-in functionality is that Firebase automatically checks for recent authentication for certain sensitive operations, but that seems to be of no use to you here.
But since your application is making API calls when the user authenticates, you can also record the time when they do so, and then check whether that was recent enough for your use-case.
If you need to check if user is authenicated - is same as reauthenication. Firebase will do their work to do some lower levels like tokens, etc. We don't have to worry about it.
guard let currentUser = Auth.auth().currentUser else {
//authenicate the user.
}
if you want to update the email address in user, the logic should be
check if the user is not nil, then update the email address.
If it is nil, then log in (anonymous or regular workflow to sign in), then update the email address.
I use this similar logic to check if the user is signed in, then do something. Otherwise, sign in as anonymous, then do same something.
The issue was quite simple: I caught the wrong error:
The error I have to catch in my case is .requiresRecentLogin . With that, everything is working fine.

Firebase Auth and Swift: Check if email already in database

I'm working on an iOS app which will use Firebase for user management (sign up, sign in, etc.)
I'm new to Firebase, but it's mostly going ok. I've connected it, I have created users and logged in, etc.
But, I'm trying to change my UI so that the "Sign up" button is initially hidden and will only appear when:
all fields are not empty
email address is valid (using regex)
email address in not already in the database
user name is not already in the database
password and confirmPassword fields are equal
I can't figure out #3 and #4.
I've been reading documentation, watching videos, chasing links all over StackO and beyond, but I can't figure it out.
Can anyone point me in the right direction?
If you are using email & password authentication, the solution is very simple.
Firebase Authentication will not allow duplicate emails so when the createUser function is executed, if the email already exists Firebase will return a emailAlreadyInUse error in the error parameter. You can then cast this to an NSError to see which one it is and handle appropriately.
So the function is like this
Auth.auth().createUser(withEmail: createEmail, password: password ) { user, error in
if let x = error {
let err = x as NSError
switch err.code {
case AuthErrorCode.wrongPassword.rawValue:
print("wrong password")
case AuthErrorCode.invalidEmail.rawValue:
print("invalid email")
case AuthErrorCode.accountExistsWithDifferentCredential.rawValue:
print("accountExistsWithDifferentCredential")
case AuthErrorCode.emailAlreadyInUse.rawValue: //<- Your Error
print("email is alreay in use")
default:
print("unknown error: \(err.localizedDescription)")
}
//return
} else {
//continue to app
}
I threw some random errors into that case statement but check the link for a complete list of all AuthErrorCodes.
You can also do this
Auth.auth().fetchSignInMethods(forEmail: user, completion: { (signInMethods, error) in
print(signInMethods)
})
I think you can check it by using this method
let ref1 = Database.database().reference().child("Users").queryOrdered(byChild: "UserName").queryEqual(toValue: "UserName enter by user")
ref1.observeSingleEvent(of: .value) { (sanpshot) in
print(sanpshot.exists()) // it will return true or false
}
and same for email.

How to set up Firebase iOS authentication email

Having looked through lots of previous questions and looking on the Firebase website documentation, it keeps leading me back to the snippet of code I need in my VC, BUT not how to actually set it up?.
Firstly in the email address verification setup on Firebase
I've by mistake put my personal email address as the 'reply to' email - do I put my personal (not business) email in there/how would I change it? Apologies for any over the top censoring (not sure what is private and not)
Secondly in my SignUpViewController what do I put as the URL String and what do I put as my IOSBundleID? Many thanks!
To change the email go to Authentication and press templates. There you have some options for your mail.
Press the pen beside noreply#yourfirebase.firebaseapp.com.
There you will have a replay to line and you can change all those settings
This is all you need to register a new user :
Auth.auth().createUser(withEmail: emailText.text!, password: passwordText.text!) {
(user, error) in
if error != nil {
print(error.localizedDescripton)
}else {
print("registration successful")
}
}
To send confirmation email to user make a call after user is created and use this method :
func sendConfirmationEmail() {
// Here you check if user exist
if self.authUser != nil && !self.authUser!.isEmailVerified {
self.authUser!.sendEmailVerification(completion: { (error) in
// Send the email
})
}
else {
// ERROR
}
}
You could now call the second method after user been created and the user will get an email

Password Change Parse swift

I have an app that allows a user to reset their password by putting their old one in a textfield and their new one in the next textfield. But in the old password textfield, the password they entered has to match the one that is registered to the currently logged in user. My app keeps crashing. Can someone help me. Here is the code. An image of the error is here.
if Password.text == (PFUser.current()?.password)! {
}else{
}
Try to add exclamation after the text: -
if Password.text! == (PFUser.current()?.password)! {
}else{
}
Edit: -
There is no way to get old password from Parse. Workaround though is.. you can first try authenticate user by giving the password which user has entered.. if authentication is successful then that means the entered old password is correct.. has been described here. Although it is android code it gives the required logic.
ParseUser.logInInBackground(ParseUser.getCurrentUser().getUsername(), currentPassword, new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
// Hooray! The password is correct
} else {
// The password was incorrect
}
}
});

Resources