Asp.Net Identity OWIN Facebook ExternalLoginInfo Email is always null - asp.net

I create auth with next code
app.UseFacebookAuthentication(new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions()
{
AppId = "1058223614196813",
AppSecret = "dd208098e2cac42996581ba2bb59e5d1",
Scope = { "email" },
});
when I try get user email, logininfo return emain null
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
but user name show me. This code work fine some time.

Facebook will not return the email for those users whose email is pending for confirmation, when a user creates new account on facebook a confirmation email is sent to the user, but if user didn't confirm his email, facebook will not return his email in user info even you added email permission in scope, until user confirms his email.

Related

How to handle email verification if trying to return to mobile app after pressing link?

Behavior Wanted: When I press the Sign Up button in my app, it sends a verification link to the specified email and navigates to a verification page within the mobile app that alerts the user that a verification email was sent. Then user can go to own email and click on the link that will verify the user and then direct them back to the verification page where it will reload the user and send them to the home page.
Question: What do I need to do in order to handle this?
Things I have done:
I have a custom domain, let's call it customdomain.com. I have set this up with firebase hosting.
I have created a dynamic link in the firebase console called customdomain.com/verify
I have created ActionCodeSettings to pass to the sendEmailVerification() function:
String url = 'https://customdomain.com/verify/';
String androidPackage = 'com.example.customdomain';
String iosPackage = 'com.example.customdomain';
ActionCodeSettings actionCodeSettings = ActionCodeSettings(url: url, handleCodeInApp: true, android: {"packageName": androidPackage, "installApp": true, "minimumVersion": 21}, iOS: {"bundleId": iosPackage}, dynamicLinkDomain: 'https://customdomain.com/verify');
Future<void> verifyEmail(ActionCodeSettings actionCodeSettings) async {
User userRegister = _auth.currentUser;
if (!userRegister.emailVerified) {
await userRegister.sendEmailVerification(actionCodeSettings);
}
}
I have set my androidManifest.xml and build.gradle to handle dynamic links.
Assumptions Made:
I can use ValueNotifier on my verification page to listen to changes in isEmailVerified.
I need to change my email template to create custom email action handler?(https://firebase.google.com/docs/auth/custom-email-handler ?)
I don't need to create a web page on my customdomain.com to handle email verification.
I will be able to parse the actionCode from the url that was sent to the email for verification.
So just a couple of questions around this. Do I need to have my own custom server in order to handle email verification like this? Can this all be done through the firebase console? When I'm sending the email, am I sending a dynamic link or is the email template sending what is in the console?
I can't find any example of someone implementing this in flutter, so if anyone can point my in the right direction. I've been struggling with thinking about what is it all that I need in order to get this done. If you need more information for clarification, please do let me know.
Do I need to have my own custom server in order to handle email
verification like this? Can this all be done through the firebase
console?
Firebase can handle all the process for email verification in Firebase Auth.
When I'm sending the email, am I sending a dynamic link or is the
email template sending what is in the console?
The email verification sent from Firebase Auth uses the template from the Firebase console.
The Flutter code for sending email verification and verifying the link in the app is similar to what's in the docs for Android.
Sending email link auth/verification
FirebaseAuth _auth = FirebaseAuth.instance;
var emailAuth = "someemail#domain.com";
void sendEmailVerification() {
var acs = ActionCodeSettings(
// URL you want to redirect back to. The domain (www.example.com) for this
// URL must be whitelisted in the Firebase Console.
url: "https://www.example.com/finishSignUp?cartId=1234",
handleCodeInApp: true,
iOSBundleId: "com.example.ios",
androidPackageName: "com.example.android",
androidInstallApp: true,
androidMinimumVersion: "12");
_auth.sendSignInLinkToEmail(
email: emailAuth, actionCodeSettings: acs)
.catchError(
(onError) => print('Error sending email verification $onError'))
.then((value) {
print('Successfully sent email verification');
});
}
Verifying link and sign in
void checkEmailLinkAuth(String emailLink) async {
if (_auth.isSignInWithEmailLink(emailLink)) {
await _auth
.signInWithEmailLink(email: emailAuth, emailLink: emailLink)
.catchError(
(onError) => print('Error signing in with email link $onError'))
.then((value) {
// You can access the new user via value.user
// Additional user info profile *not* available via:
// value.additionalUserInfo.profile == null
// You can check if the user is new or existing:
// value.additionalUserInfo.isNewUser;
var userEmail = value.user;
print('Successfully signed in with email link!');
});
}
}

How to verify an email in firebase auth in flutter?

I've created a login screen using firebase & flutter and Everything is going okay but I want the user to sign in with a real email (verified) not any email.
if the user clicks signs in button with an email like that : shsuhsafk#uisl.com, it will accept this email.
how to verify that the email isn't fake and actually belong to a real address.
In order to really verify the users e-mail address you need to send a verification mail which requires action from the user.
Only checking if the address exists is insufficient as the e-mail address could belong to anyone.
You can set up a mail template in your Firebase Console and use the following code to send the verification mail.
FirebaseUser user = await _firebaseAuth.createUserWithEmailAndPassword(email: email, password: password);
try {
await user.sendEmailVerification();
return user.uid;
} catch (e) {
print("An error occured while trying to send email verification");
print(e.message);
}
}
String email = "user#example.com";
try {
String link = FirebaseAuth.getInstance().generateSignInWithEmailLink(
email, actionCodeSettings);
// Construct email verification template, embed the link and send
// using custom SMTP server.
sendCustomPasswordResetEmail(email, displayName, link);
} catch (FirebaseAuthException e) {
System.out.println("Error generating email link: " + e.getMessage());
}
Please refer Below link for more info: https://firebase.google.com/docs/auth/admin/email-action-links

Get Identifier field from Firebase Auth Console

I'm trying to get the email from the user that's currently authenticated using the Facebook Firebase provider. The email is listed under the Identifier field inside the Project's Firebase Authentication Console:
However when I invoke firebase.auth().currentUser the user information loads, however the email field is null. Any ideas on how to get the Identifier (which is where I see the email address) from Firebase? Is this even possible?
Below is the code I'm using:
componentDidMount() {
let user = firebase.auth().currentUser;
let name, email, photoUrl, uid, emailVerified;
if (user !== null) {
name = user.displayName;
email = user.email;
photoUrl = user.photoURL;
emailVerified = user.emailVerified;
uid = user.uid;
console.log(name, email, photoUrl, emailVerified, uid);
}
}
Note: Prevent creation of multiple accounts with the same email address is enabled in Firebase. Also, Facebook API permissions are set to ['public_profile', 'email']
After some testing and debugging I found that the email field will be populated if you're using a regular Firebase Email/Password Sign In method. However, if you're using another Sign In provider method such as Facebook, the email field will appear null (not sure why).
Further inspection of the user object revealed a providerData property.
It's an array that contains all the provider information (including the email address):
So, I updated my code to accommodate this:
componentDidMount() {
let user = firebase.auth().currentUser;
let name, email, photoUrl, uid, emailVerified;
if (user) {
name = user.displayName;
email = user.email;
photoUrl = user.photoURL;
emailVerified = user.emailVerified;
uid = user.uid;
if (!email) {
email = user.providerData[0].email;
}
console.log(name, email, photoUrl, emailVerified, uid);
}
}
In my case, the getEmail() method always returns data for three sign-in possibilities (if user gave authorization to my app to show/use email): Sign in with Email, Sign in with Google, Sign in with Facebook.
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
Log.v(TAG,"user.getEmail():"+user.getEmail());
if (user.getEmail() == null){
// User did not authorize the app to show/user email
}
else {
Log.v(TAG,"user.getEmail():"+user.getEmail());
}

Firebase Convert Anonymous User Account to Permanent Account Error

Using Firebase for web I can successfully create an anonymous user. I can also create a new email/password user. But when trying to convert an anonymous user to a email/password user I get error:
auth/provider-already-linked
User can only be linked to one identity for the given provider.
Firebase documents the procedure here under section "Convert an anonymous account to a permanent account" here:
https://firebase.google.com/docs/auth/web/anonymous-auth
Here's the account link code. Anonymous user is signed in.
return firebase.auth().createUserWithEmailAndPassword(email, password).then(newUser => {
// Credential is being successfully retrieved. Note "any" workaround until typescript updated.
let credential = (<any>firebase.auth.EmailAuthProvider).credential(email, password);
firebase.auth().currentUser.link(credential)
.then(user => { return user; })
.catch(err => console.log(err)); // Returns auth/provider-already-linked error.
});
You should not call createUserWithEmailAndPassword to upgrade the anonymous user. This will sign up a new user, signing out the currently signed in anonymous user.
All you need is the email and password of the user. IDP providers (e.g. Google, Facebook), on the contrary, will require to complete their full sign in flow to get their tokens to identify the user. We do recommend to use linkWithPopup or linkWithRedirect for these, though.
Example:
// (Anonymous user is signed in at that point.)
// 1. Create the email and password credential, to upgrade the
// anonymous user.
var credential = firebase.auth.EmailAuthProvider.credential(email, password);
// 2. Links the credential to the currently signed in user
// (the anonymous user).
firebase.auth().currentUser.linkWithCredential(credential).then(function(user) {
console.log("Anonymous account successfully upgraded", user);
}, function(error) {
console.log("Error upgrading anonymous account", error);
});
Let me know if that works!
After you log in as an Anonymous user, run this code to raise Popup and connect your anon user wit some OAUTH provider
const provider = new firebase.auth.FacebookAuthProvider()
firebase.auth().currentUser.linkWithPopup(provider)
console.log(provider)
For iOS, Swift 5 to create a credential use
EmailAuthProvider.credential(withEmail: , password: )
example:
let credential = EmailAuthProvider.credential(withEmail: emailTextField.text!, password: passwordTextField.text!)
Auth.auth().currentUser?.link(with: credential, completion: { (authDataResult: AuthDataResult?, error) in
// ...
})

Firebase confirmation email not being sent

I've set up Firebase email/password authentication successfully, but for security reasons I want the user to confirm her/his email.
It says on Firebases website:
When a user signs up using an email address and password, a confirmation email is sent to verify their email address.
But when I sign up, I doesn't receive a confirmation email.
I've looked and can only find a code for sending the password reset email, but not a code for sending the email confirmation.
I've looked here:
https://firebase.google.com/docs/auth/ios/manage-users#send_a_password_reset_email
anyone got a clue about how I can do it?
I noticed that the new Firebase email authentication docs is not properly documented.
firebase.auth().onAuthStateChanged(function(user) {
user.sendEmailVerification();
});
Do note that:
You can only send email verification to users object whom you created using Email&Password method createUserWithEmailAndPassword
Only after you signed users into authenticated state, Firebase will return a promise of the auth object.
The old onAuth method has been changed to onAuthStateChanged.
To check if email is verified:
firebase.auth().onAuthStateChanged(function(user) {
if (user.emailVerified) {
console.log('Email is verified');
}
else {
console.log('Email is not verified');
}
});
After creating a user a User object is returned, where you can check if the user's email has been verified or not.
When a user has not been verified you can trigger the sendEmailVerification method on the user object itself.
firebase.auth()
.createUserWithEmailAndPassword(email, password)
.then(function(user){
if(user && user.emailVerified === false){
user.sendEmailVerification().then(function(){
console.log("email verification sent to user");
});
}
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode, errorMessage);
});
You can also check by listening to the AuthState, the problem with the following method is, that with each new session (by refreshing the page),
a new email is sent.
firebase.auth().onAuthStateChanged(function(user) {
user.sendEmailVerification();
});
The confirmation email could be in your spam folder.
Check your spam folder.
You can send verification email and check if was verified as follow into the AuthListener:
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
//---- HERE YOU CHECK IF EMAIL IS VERIFIED
if (user.isEmailVerified()) {
Toast.makeText(LoginActivity.this,"You are in =)",Toast.LENGTH_LONG).show();
}
else {
//---- HERE YOU SEND THE EMAIL
user.sendEmailVerification();
Toast.makeText(LoginActivity.this,"Check your email first...",Toast.LENGTH_LONG).show();
}
} else {
// User is signed out
Log.d(TAG, "onAuthStateChanged:signed_out");
}
// [START_EXCLUDE]
updateUI(user);
// [END_EXCLUDE]
}
};
if you're using compile "com.google.firebase:firebase-auth:9.2.0" and
compile 'com.google.firebase:firebase-core:9.2.0' the method sendEmailVerification() will not be resolved until you update to 9.8.0 or higher. It wasted most of time before I figured it out.
I have been looking at this too. It seems like firebase have changed the way you send the verification. for me
user.sendEmailVerification()
did not work.
If you get an error such as user.sendEmailVerification() doesn't exist.
use the following.
firebase.auth().currentUser.sendEmailVerification()
It's not the answer to the question but might help someone.
Don't forget to add your site domain to the Authorised domains list under Sign-in-method
You could send a verification email to any user whose email is linked to the Firebase Auth account. For example, in Flutter you could do. something like :
Future<void> signInWithCredentialAndLinkDetails(AuthCredential authCredential,
String email, String password) async {
// Here authCredential is from Phone Auth
_auth.signInWithCredential(authCredential).then((authResult) async {
if (authResult.user != null) {
var emailAuthCredential = EmailAuthProvider.getCredential(
email: email,
password: password,
);
authResult.user
.linkWithCredential(emailAuthCredential)
.then((authResult,onError:(){/* Error Logic */}) async {
if (authResult.user != null) {
await authResult.user.sendEmailVerification().then((_) {
debugPrint('verification email send');
}, onError: () {
debugPrint('email verification failed.');
});
}
});
}
});
}

Resources