After I have run the required methods to unlink the password provider, it still appears when I query it using user.providerData. The FirebaseAuth-Console registers that the password providers has been unlinked, also if I run the unlink method again I get the appropriate error: "User was not linked to an account with the given provider."
Doing the same with facebook or google login runs without problems. The error only occurs if I unlink an additional password login.
Only after I logout and login again the query is correct.
All other changes are displayed immediately/correctly. Google link/unlik, facbeook unlink/link. Even the password link method is registered instantly in user.providerData, only the unlink method is not registered immediately.
Any Ideas?
Flow:
1. Query providers IDs
1.2. result -> user.providerData = facebook.com, password
2. Execute unlink "password" provider method (runs without error)
3. Query provider IDs again
3.1. ❌ result -> user.providerData = facebook.com, password
Query method:
if let user = Auth.auth().currentUser {
for profile in user.providerData {
// Id of the provider
print(profile.providerID)
}
} else {
// No user is signed in.
}
Unlink method:
Auth.auth().currentUser?.unlink(fromProvider: "password", completion: { (user, error) in
if let error = error {
print(error)
} else {
print("successfully unlinked eMail & password login")
}
})
Google has confirmed to me that this is a current bug.
They told me they were working on the issue, and will be available on the next release, but can't provide any details or exact timeline when this would be available.
Related
I have the following logic for allowing guest users to login to my app:
(1) Login as Anonymous.
(2) Check if Facebook is logged.
(3) If it is logged to Facebook, link to Anonymous.
(4) If link fails, Login to firebase passing facebook token to Firebase
If I am not logged in Facebook the Anonymous ID given by firebase after step (1) is always the same. However, the first time I login to Facebook, I link the account to firebase as in step (3). And from that onwards, I get a different Anonymous ID every time I go through the login process.
Question 1. Will the Anonymous ID in step (1) ALWAYS be the same until I login to Facebook for the first time?
Question 2. What is the best login flow to allow users to save data in the backend as guests, and link to facebook later when the user decides to do so?
Here is my swift code that implements my pseudo code:
func login() -> Promise<AuthCredential?> {
// Login as Anonymous. Check if FB is logged. If it is, link to Anonymous. If fails, pass FB token to Firebase
print("........................")
print("Starting Login")
return Promise { seal in
Auth.auth().signInAnonymously() { (authResult, error) in
print("-Done Login Anonymously", authResult?.credential, Auth.auth().currentUser?.uid)
if let error = error {
print("-DID NOT SIGNED UP WITH FIREBASE:", error)
seal.reject(error)
} else {
if AccessToken.isCurrentAccessTokenActive { // If Facebook token is active exchange for Firebase
let credential = FacebookAuthProvider.credential(withAccessToken: AccessToken.current!.tokenString)
print("-Loggged with FACEBOOK!!!!", credential)
Auth.auth().currentUser!.link(with: credential) { (result, error) in
print("-Linked Account!!!!??????????", result as Any, error as Any)
if error != nil {
Auth.auth().signIn(with: credential) { (authResult, error) in
print("-Signed UP in Firebase USIG FB. No Linking")
if let error = error {
print("-DID NOT SIGNED UP WITH FIREBASE:", error)
seal.reject(error)
} else {
print("-DID SIGNED UP WITH FIREBASE using FB:", Auth.auth().currentUser?.uid)
seal.fulfill(authResult?.credential)
}
}
}
}
}
// print("-Done Login", Auth.auth().currentUser?.uid)
// seal.fulfill(authResult?.credential)
}
}
}
}
The API documentation for signInAnonymously (javascript) reads:
If there is already an anonymous user signed in, that user will be
returned; otherwise, a new anonymous user identity will be created and
returned.
You probably only want to call signInAnonymously if there is no user signed into the app. It's best to wait to see if a user is already signed in using an auth state listener, as the sign-in process is not immediate.
Once you link the anonymous account with a full account, you should probably not call signInAnonymously again, since you probably want the user to stay signed in with their full account and no create another new anon account.
My app is having facebook & email password login with firebase. Now for those user who are signed with Facebook, I don't want to verify their emails. but in Auth.auth().currentUser?.isEmailVerified its return false always. so is there any other method to detect user is logged in with facebook. I know i can store value inside user default before login but after uninstall & reinstall app i will lost that userdefault. while firebase keep user logged in. i can use keychain for that but if firebase directly provide that then that will make easy for coding.
I find one solution with firebase methods:
if let providerData = Auth.auth().currentUser?.providerData {
for userInfo in providerData {
switch userInfo.providerID {
case "facebook.com":
print("Facebook Login")
//isVerifiededUser = true
default:
print("provider is \(userInfo.providerID)")
}
}
}
You can use:
if let user = Auth.auth().currentUser {
if FBSDKAccessToken.current() != nil {
// logged in using facebook
}
else {
// logged in using manual email/password method
}
}
so you can send verification emails to only those who are logged in using email/password method.
Firebase doesn't provide a method to show which was the first method used to create Firebase account. You will have a list of the all the providers attached to a firebase user with their emails/ phone number attached to them.
Firebase by default only set emails verified for Google SignIn, for other providers Firebase behavior is to set false (although some times it do set the email verified true randomly). The reason is that Firebase cannot guarantee that email is verified by facebook on their platform but incase of Google firebase has trust.
One option is you always send verification email no matter facebook or Email Auth. Second is that you ditch Email password login and instead use new Email Link Authentication, which eliminates the email auth needed in password login.
EDIT:
if you only allow one method to be used at a time then you can get the providers list from the firebase user and check if the providers list has 'password' signin method present, send a verification email after checking email verified, else don't send the email and continue the app
Here is the resource to email link authentication: https://firebase.google.com/docs/auth/ios/email-link-auth
This code means that at some point the user registered using Facebook, but it does not mean that at this point the user is using this provider for access. If the user has these providers ["google.com", "facebook.com"] it will also return true . 😊🖤
fileprivate func userHasFBProvider() -> Bool{
var fBProvider = false
guard let providerData = Auth.auth().currentUser?.providerData else {
return fBProvider
}
for userInfo in providerData {
switch userInfo.providerID {
case "facebook.com":
fBProvider = true
default:
fBProvider = false
}
}
return fBProvider
}
I have set up a Swift App with the Auth0 Web Login and everything works fine. Then i have tried to implement the "Lock" login with the result that social media login works perfectly well, but i cannot login via the username-password method.
On my Auth0 database, the signed-up user shows up (indicating that sign up of new username-passoword user actually work) and testing the login itself on the Auth0 Homepage works fine as well. Just when trying to login with the Lock widget, i get an error: "We're sorry, something went wrong when attempting to log in.". I also tried verifying the registered E-Mail, but that did not solve the issue either.
Any ideas, what might go wrong here?
After also pointing that issue out to Auth0/Lock support, a solution was found. Maybe this helps people, having the same problem: When using the Lock client inside some VC:
Lock
.classic()
.withOptions {
$0.scope = "openid profile"
$0.oidcConformant = true
$0.logHttpRequest = true
}
.withStyle {
$0.title = "App Name"
}
.onAuth { credentials in
print("successful login")
}
.onError { error in
print("Failed with error \(error)")
}
.present(from: self)
instead of the web login:
Auth0
.webAuth()
.audience("https://alienbash.eu.auth0.com/userinfo")
.start {
switch $0 {
case .failure(let error):
// Handle the error
print("Error: \(error)")
case .success(let credentials):
// Do something with credentials e.g.: save them.
// Auth0 will automatically dismiss the hosted login page
print("Credentials: \(credentials)")
}
}
one has to make sure to change "Grant_Type" the Auth0 client settings to also allow the "Password" Grant. In order to do that, in your Auth0 client go to:
Settings --> Advances Settings --> Grant Types
and make sure to check "Password as this checkmark is unchecked by default when creating a new Auth0 client and will be inevitable when using the "Lock" client.
I'm new to Firebase and iOS and I was wondering if someone knew how to link multiple oAuth Providers. I followed the Firebase docs and tried to implement this function:
func firebaseSignInWithLink(credential: FIRAuthCredential) {
FIRAuth.auth()?.signIn(with: credential, completion: { (user, error) in
if error != nil {
debugPrint("APP: there has been an error signing into firebase, perhaps another account with same email")
debugPrint("APP: \(error)")
// if existing email, try linking
FIRAuth.auth()?.currentUser?.link(with: credential, completion: { (user, error) in
if error != nil {
debugPrint("APP: there has been an error signing into firebase")
debugPrint("APP: \(error)")
}
else {
debugPrint("APP: successfully signed into firebase")
}
})
}
else {
debugPrint("APP: successfully signed into firebase")
}
})
}
The FIRAuth.auth()?.currentUser?.link function never gets called despite the above debugPrint("APP: \(error)") being called. Because this doesn't work, I keep getting the error below:
Optional(Error Domain=FIRAuthErrorDomain Code=17007 \"The email address is already in use by another account.\" UserInfo={NSLocalizedDescription=The email address is already in use by another account., error_name=ERROR_EMAIL_ALREADY_IN_USE, FIRAuthErrorUserInfoEmailKey=example#gmail.com})"
Any help would be greatly appreciated! Thank you :D
I believe you are confused by the instructions. On firebase documentation it reads
To link auth provider credentials to an existing user account:
Sign in the user using any authentication provider or method.
Complete the sign-in flow for the new authentication provider up to, but not including, calling one of the FIRAuth.signInWith methods. For example, get the user's Google ID token, Facebook access token, or email and password.
Get a FIRAuthCredential for the new authentication provider
So you should not call the method FIRAuth.signInWith. I should also point out that you want to create a link to an existing account, so you should have signed in first and then you can link it. This is why you should have a currentUser.
It occurred because of unchecking "Multiple accounts per email address setting firebase setting" from firebase console.
I am currently using Parse to create and log in users for my iOS app. After a user signs up with a new account, Parse does not log them in––it just clears the text fields. Some users get confused thinking the signup was unsuccessful, and try to put their information in again, prompting the "username taken" alert. How can I modify the Parse login so that it automatically logs in the user once they create a successful account? (I currently have a ParseLoginHelper class––would I make this modification in the PFSignUpViewControllerDelegate extension?)
If anyone has example code they would like to share in their answer, please note that I'm using Swift for my project.
When you are signing up (register) a new users you don't need to call the logIn function again in order to log them in to the app.
After the signing up process they are already logged in. In order to check if they are logged in you can check if the current user is not nil
if PFUser.currentUser() != nil {
}
At the end your sign up code should look like the following:
let user = PFUser()
user.username = "USERNAME"
user.password = "PASSWORD"
user.email = "EMAIL"
// add more fields
user.signUpInBackgroundWithBlock {
(succeeded: Bool, error: NSError?) -> Void in
if succeeded {
// here the current user should not be nil.
// if it is then please check for sessionToken
if PFUser.currentUser() != nil {
// user is logged in
}
}
}