is unique email address from Apple when performing 'Sign in using Apple' always change? - ios

I am trying to make login using OAuth2 using Apple Sign in. and I need to save the user email to the server.
after reading Sign in with Apple and authenticate with Firebase documentation , it said that
Unlike other providers supported by Firebase Auth, Apple does not
provide a photo URL.
Also, when the user chooses not to share their email with the app,
Apple provisions a unique email address for that user (of the form
xyz#privaterelay.appleid.com), which it shares with your app. If you
configured the private email relay service, Apple forwards emails sent
to the anonymized address to the user's real email address.
apple will generate unique fake email like xyz#privaterelay.appleid.com if the user refuses to share their original email.
if the user logout and then login again, will the fake email will be the same? or apple will generate a new fake email like new123#privaterelay.appleid.com ?

Related

Firebase Auth link provider Google sign in issue?

At the first time, while signup with Gmail and password, firebase saved the credentials correctly. But the next time, I Login with Firebase Google authentication with the same Gmail which i gave while signup, the credentials are overriding in firebase account. After overriding the credentials, we are not able to login using that signup credentials. Can anyone explain how to achieve this?
What happened
In the first screenshot you signed in with the email+password provider of Firebase. While this is a valid sign-in method, it means that anyone could've entered that email address, even if they don't actually have access to the Google account for that gmail address.
There is no security risk here, but the level of trust we can put in the value of email address is low. For this reason the emailVerified property of the account is marked as false and you'll typically want to require that the user verify their email address before allowing them to continue.
In the second screenshot, the user signed in with the same email address, but now with the google.com provider of Firebase. This means that Google now verified already that the user has access to the underlying gmail address of the account. Since the google.com provider is the trusted provider for #gmail.com accounts, the system replaces the previous account.
Also see:
Authentication using Facebook at first and then Google causes an error in Firebase for Android
Firebase Overwrites Signin with Google Account
Trying to understand Firebase Authentication one account per email address and trusted providers
What you can do
You'll typically want to prevent multiple users from signing up with the same email address. For this, you'll want to configure Firebase to only allow a single account per email address in the console, and then use account linking so that the two (email+password and google.com) accounts in your scenario are merged.
Did you verify the email or phone number from the first login attempt? If not, this is by design:
After sign-in completion, any previous unverified mechanism of sign-in will be removed from the user and any existing sessions will be invalidated. For example, if someone previously created an unverified account with the same email and password, the user’s password will be removed to prevent the impersonator who claimed ownership and created that unverified account from signing in again with the unverified email and password.
Source
I just ran into this problem and here is a longer and more in depth description. (Things change often, this was true in Nov 2021.)
SHORT VERSION: As #Frank van Puffelen said, this is by design. The issue is that email+password is not a trusted provider usually, so a trusted provider like Google Authentication overwrites that method. It does this silently (I think, didn't check every field in GoogleSignInAuthentication object.)
It does auto-link after a password reset OR the email is verified via a link. See https://firebase.flutter.dev/docs/auth/usage/#verifying-a-users-email on code to do that.
Also: I don't recommend turning off One account per email address as some others suggests . See the reason for that at the end.
"Weird" Behavior under default One account per email address
In my app, the following happens.
SignUp via email+password for testUser1234#gmail.com.
creates an account for c_example_account#gmail.com with provider=Email/Password as indicated by the envelope/mail icon in the firebaseAuth dashboard.
LogOut and re-signin via Google Sign In for c_example_account#gmail.com
The provider is changed. Old provider is Email/Password icon (envelope). New provider is Google icon. (like the bottom three accounts in the screenshot). Note also that the User UID is the same. So anything anything linked to that User UID is still okay.
Since the Email/Password login method (AKA) provider was removed for c_example_account#gmail.com, the user can't login with that method anymore. IMPORTANTLY: This is done silently without the user getting any notification that the Email/Password login was removed.
Trying to sign on using Email/Password will result in an error Incorrect Password. Note: one might expect it to give an error like "Only Google Sign-In is available", but it doesn't. Contrast this to when the email doesn't exist (like trying garbage#123457.com), which has an error Email is not found...
Now, it gets a little weirder...
Suppose the user uses "Reset Password" like being called like this
Future<void> resetPassword(String email) async {
await _firebaseAuth.sendPasswordResetEmail(email: email);
}
Then, the firebaseAuth console has TWO methods for the same USER UID. See the second and third line in the screenshot.
Now, both methods are allowed. The difference is that the first time was a createUserWithEmailAndPassword() like
await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
...but this time it was created via a "Reset" event
Future<void> resetPassword(String email) async {
await _firebaseAuth.sendPasswordResetEmail(email: email);
}
... that gave a link via email sent by firebaseAuth service. In this case, the email was verified.
Recap: Now both methods work. The two methods being (1) Google authentication and (2) Email/Password. In Google parlance, the accounts have been linked: https://firebase.google.com/docs/auth/android/account-linking. Linking means One User UID, multiple login methods
Why the funky behavior when Email/Password is created in two different methods?
~~I couldn't find this documented in firebaseAuth, maybe because I didn't look hard enough or maybe because it's not a common issue. ~~
UPDATE: This behavior is documented in an issue comment from April 2020.
I think the reason is because the _firebaseAuth.createUserWithEmailAndPassword version has an unverified email. So, anyone can create an account for anyone else assuming that the email+password combination doesn't exist. For example, I could create an account with username president#whitehouse.gov without actually having access to that email. If the actual president logged in via Google Authentication, then I'd have bogus access to that user's info. Except that the clever google engineers decided that the verified Google Authentication then triggers the deletion of the unverified Email/Password provider/account instance.
In short, the logic might be: verified trumps/overrides unverified. See https://firebase.google.com/docs/auth/users#verified_email_addresses
Again, none of this is documented explicitly for Email/Password. But it is hinted at in the documentation, like if a Facebook Auth account gets over-written by a Google Auth.
Snapshot of the Verified Email details
Copied from: https://firebase.google.com/docs/auth/users#verified_email_addresses
Bolded added by me, for emphasis
In some situations, Firebase will automatically link accounts when a
user signs in with different providers using the same email address.
This can only happen when specific criteria are met, however. To
understand why, consider the following situation: a user signs in
using Google with a #gmail.com account and a malicious actor creates
an account using the same #gmail.com address, but signing in via
Facebook. If these two accounts were automatically linked, the
malicious actor would gain access to the user's account.
The following cases describe when we automatically link accounts and
when we throw an error requiring user or developer action:
User signs in with an untrusted provider, then signs in with another untrusted provider with the same email (for example, Facebook followed
by GitHub). This throws an error requiring account linking.
User signs in with a trusted provider, then signs in with untrusted provider with the same email (for example, Google followed by
Facebook). This throws an error requiring account linking.
User signs in with an untrusted provider, then signs in with a trusted provider with the same email (for example, Facebook followed
by Google). The trusted provider overwrites the untrusted provider.
If the user attempts to sign in again with Facebook, it will cause an
error requiring account linking.
User signs in with a trusted provider, then signs in with a different trusted provider with the same email (for example, Apple
followed by Google). Both providers will be linked without errors.
You can manually set an email as verified by using the Admin SDK, but
we recommend only doing this if you know the user really does own the
email.
Why not turn off One account per email address
By default, the setting One account per email address is active as #Deva wrote. But, unchecking this means that there are two different accounts (User UIDs) for the same email. One via Email/Password and one via Google Authentication. They will have separate User UIDs in Firebase Auth, so that may confuse you. Furthermore, if you manually link in your app two User UIDs, this creates a security hole: Someone can create an account without email verification to get access to an existing account. So don't do that.
Related StackOverflow questions and links
https://stackoverflow.com/a/60276351/233382
why i can't link email/password to the same email exist in google sign in provider in firebase flutter?
https://github.com/firebase/firebase-ios-sdk/issues/5344#issuecomment-618518918

Sign in with Apple - Hide email

On 'Sign in with Apple' If the user opted for “Hide my Email”, he will be registered with a private email id. Again if the same user tries to Register with the original email address (with any social media account or with original email id), he will be treated as a different user?
How is it possible to make sure we have a unique user in the database after registration?
As per apple doc: link (https://support.apple.com/en-in/HT210425)
If you choose to hide your email when you create an account with an
app or website using Sign in with Apple, a unique, random email
address is created so your personal email can stay private.
To answer your question:
If user sign-in with actual email id from another platform/social
login then this will be a new user for you.
Don't use the email address as an unique identifier, you can use the "sub" parameter returned in the identity Token JWT, the value of this parameter is the same for the same Apple ID user and is unique, across all apps that belongs to your Apple developer account / organization.

Sign in with Apple ASAuthorizationAppleIDCredential returns random email when user select 'Hide My Email' option for iOS

When I go through the Sign in with apple I am getting first time exact email address and basic details of the user which I want but second time in response there is no email field in response.
My concern is that I want email address of the user so in future I can send notification email to that particular user. but apple gives random created email, in reality that doesn't exists. How to contact to user in future by email?
You might have to register the outbound email with apple, check this for more information on using the private email provided also look at the sign in with apple docs here.
As far as I know the random created email apple gives is actually connected to user's actual mail id. All the mail you send will be forwarded to it. But they can unlink their mail in future. This gives users some privacy and protection from spamming.
When I was finding solution I got to know, we have to pass an email address for following:
The email addresses you register will be able to send and receive messages to and from customers using Apple’s private email relay service.
Once I added this I am able to send and receive the emails.
https://developer.apple.com/account/resources/services/configure
Short answer :
You need to add sender email id or domain name into to your developer account.
Add your email and domain name.
Long answer
You need to follow below steps:
Log in with your developer account in https://developer.apple.com
Goto More section. Please refer below screenshot.
Click on configure button. Please refer below screenshot.
Add domain and email address, You want to communicate.
Add email and domain here

How to combine local and Facebook users in iOS app

I want to give the opportunity for a user of an app to register/login with Facebook or by creating an account. I know that I can get the user's Facebook account email address, and their first and last names. That's basically the only information for creating a 'local' app account, apart from a password. How can I make sure that if that person logs in to Facebook on another device, that their two devices are linked to the same 'local' account? (i.e if they choose to sign in with Facebook with 2 devices, I only want one local account to be created on my server for that user).
Ideally, I want the login schemes for both to be identical. So if that user logs in with Facebook, I can check (securely) that the FB account is linked to a 'local' account, and automatically log that device in without making the user type in a password. Is this possible?
Edit: The 'local' users will be stored in a database on my server, and the front end will be done in Python running alongside the API for the app. Note that 'local' is just referring to the fact that it uses my app web service rather than an external social network.
You can do that within your users database as per below:
assuming you store the user data in a table named userinfo, this table should contain user e-mail, first name, etc..
Add another column in this table named fbemail.
If users signs in using web service, his email will be saved in the email field & the fbemail should be null, if signs in using FB, then both email & fbemail should be the extracted email.
when the user uses FB login, check the fbemail field, if not found, then this is a new user, add his data, if not, then this is a returning user, no need to add his data.
Option 1.
You can identify your Facebook user by his Facebook User ID. If he logs in using Facebook on other device you know it cause he sends you his Facebook User ID in the authentication process. He also sends you Facebook access token which you validate contacting Facebook to see if it is correct. Using this approach you have to have a different authentication scheme for Facebook user and "normal", email user.
Option 2.
To have the same login scheme you can use Facebook to get user email and prepend it in the email text field in your registration screen. The user would need to additionally provide a password. This means that you are not really doing a Login with Facebook, but use Facebook to obtain an email (and any additional information) so the user does not have to type it.
This is an old post but still very valid. You are correct, anybody who has your FB email could potentially access your server rest-api and log into it. To access a backend service you will need to use as password the FB access token generated during the FB log-in. This is stored in the device keychain and can be retrieved as:
NSString *accessToken = [[FBSDKAccessToken currentAccessToken] tokenString];
NSString *userID = [[FBSDKAccessToken currentAccessToken] userID];
The topic of using a FB authentication system in parallel to a custom login/registration system is covered in this FB guide: Using Facebook Login with Existing Login Systems.
In sum, different scenarios need to be addressed:
A person signs up for your app using their email and password, but later they want to use Facebook Login to obtain data from their Facebook account, to post to their timeline, or just to use to log in with in future.
A person signs up for the app using their email and password, but later chooses to log in with Facebook separately. This guide assumes that the email supplied first and the primary email associated with their Facebook account are the same.
A person signs up for the app using Facebook Login and later wants to log in to this account using an email address and password.
The guide recommends using two different tables for the FB log-in and the custom login.

Authenticate gmail/yahoo user in ios app via his email id & password

In my mobile app, I want to authenticate gmail/yahoo user via his email id & password to access my mobile app (I have done this with the Facebook). After lots of research, found repeated questions like question1, question2 and got this reference as Google api doc.
I have gone through the reference site and its code but not understood which is the domain and where to send which request.
Is there any way to authenticate gmail/yahoo user via his email id & password? Please help.

Resources