So I had a problem where Omni-Auth Facebook wasn't returning an email address for SOME (20-30%) user accounts, therefore the accounts wouldn't be registered because of an "email can't be blank error."
So I decided to solve this by automatically generating an email address based on the user's facebook ID if omniauth couldn't get the email address...
Now... of course... the problem with my solution (as you'll see below) is that it started saving the auto-generated email address REGARDLESS of whether or not omniauth was returning an email address. (For example my email always worked fine, but it was replaced with 123213#facebook.com)
Basically what I want is this: if a user has already supplied an email address then it just stays with the original. If they haven't, and the email address can't be gotten from omniauth, then it generates a new one.
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.email = "#{auth.provider}-#{auth.uid}#liquid-radio.com"
user.password = user.password_confirmation = SecureRandom.urlsafe_base64(n=6)
if auth.provider == "facebook"
user.name = auth.info.name
user.email = auth.info.email = "#{auth.uid}#facebook.com"
else
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
end
user.save
end
end
You'll probably want to move this line:
user.email = "#{auth.provider}-#{auth.uid}#liquid-radio.com"
down into the "else" case, since it only (presumably) applies to non-Facebook users.
Aside from that, try changing this:
user.email = auth.info.email = "#{auth.uid}#facebook.com"
to this:
user.email ||= auth.info.email || "#{auth.uid}#facebook.com"
A breakdown of what this does:
if the user already has an email, it doesn't change it
if there's a value in auth.info.email and the user doesn't have an email yet, set it
if there isn't a value in auth.info.email, punt and use the generated version
You could write this out long-form in Ruby as:
if user.email
# do nothing
elsif auth.info.email
user.email = auth.info.email
else
user.email = "#{auth.uid}#facebook.com"
end
Note: the solution above will not work if the liquid-radio.com line is still above the if auth.provider part - the user will ALWAYS have a value in the email field in that case.
Another note: this code will not update a user's email from their Facebook auth if it changes. This may or may not be what you want.
Related
I made the following login function:
#objc func handleSignIn() {
guard let email = emailField.text else { return }
guard let pass = passwordField.text else { return }
Auth.auth().signIn(withEmail: email, password: pass) { user, error in
if error == nil && user != nil && (user!.user.isEmailVerified){
self.dismiss(animated: false, completion: nil)
}; if user != nil && !(user?.user.isEmailVerified)! {
self.lblStatus.text = "Please Verify Your Email"
}
else {
self.lblStatus.text = "Error logging in: \(error!.localizedDescription)"
resetForm()
}
}
Yet the user can still log in without verifying their email despite my attempts to prevent this with the && (user!.user.isEmailVerified) stipulation. What am I missing here?
The completion of a sign in just means that the user identified themselves, and you know which account represents their chosen identity. A sign-in does not imply authorization to do anything with that account, other than to update its profile information.
You'll notice there's a bit of a chicken and egg problem here. A sign-in has to complete successfully in order to get a User object, and that user object has the property which indicates if their email has been verified. So you have to allow a sign-in if you want read that property.
You could, in theory, sign the user out immediately if they haven't verified, but all that does is prevent them from requesting another email verification, in case they deleted the first one, or it wasn't able to be delivered. So now you just have an upset user who can't take any action to resolve the issue.
If you want to prevent the user from doing anything in other Firebase products until they're verified, you should use security rules to prevent whatever read and write access shouldn't be allowed. You can check the email verification flag in your rules. Look into using auth.token.emailVerified. Example for Realtime Database here.
I set up a website using web2py and I'm looking for help to setup an email notification that will email the the person when they get a private message.
I already have the system able to have a semi message system/private message and I'm wondering how do I integrate that all together so that if a person gets a message, the system can automatically email that user. I been looking around to how to set it up but no luck for myself.
Thank you.
Edit: Before I start trying to integrate the messaging system, I wanted to test it out with the registration since that's the only thing I could find about web2py and email notification.
Edit2: Got the register to work and it says "email is sent". However, no actual email is sent.
This is all in the Models, menu.py. Also tried putting this in the controller, default.py.
auth.settings.register_next = URL('Welcome')
def Welcome():
User_Email = auth.user.email
mail.send(User_Email,'Welcome To website','Welcome To website')
if request.vars.lan == 'En':
redirect('index',vars={'lan':'En'})
else:
redirect('index')
#from gluon.tools import Mail
#mail = Mail()
#mail.settings. = True
#mail = auth.settings.mailer
mail = auth.settings.mailer
mail.settings.tls = False
mail.settings.server = "tls://smtp.gmail.com:587"
mail.settings.sender = "...#gmail.com"
mail.settings.login = "...#gmail.com:password"
# sends an verification e-mail upon registration
auth.settings.registration_requires_verification = True
def send_email(user, subject):
message = "" "Multi line string for %(first_name)s......"
message = open("somefile.html", "r").read()
# you also have the option to include everyone in bcc=[...]
mail.send(to=user.email,
subject=subject,
message=message % user)
user = db(db.auth_user).select()
for user in user:
send_email(user, "some subject")
Also have in the controller/default.py
def login():
auth.settings.registration_requires_verification = True
auth.settings.registration_requires_approval = False
auth.settings.reset_password_requires_verification = True
I have a Grails project (v2.4.2) that is making use of the spring-security-facebook:0.17 plugin to authenticate via Spring Security. At first sight, all seems well. However, there is a large set of users that for some unknown reason I cannot access their email address. I am using spring social to grab the email. I have permission and it is set in the scope. Here is a code snippet where I authenticate a new user:
log.info("Create domain for facebook user $token.uid")
//Use Spring Social Facebook to load details for current user from Facebook API
log.info("create: FacebookAuthToken: $token")
log.info("created FacebookAuthToken.FacebookAccessToken = ${token.accessToken}")
Facebook facebook = new FacebookTemplate(token.accessToken.accessToken)
org.springframework.social.facebook.api.User fbProfile = facebook.userOperations().getUserProfile()
// Check if email is actual granted because in production some are coming back null
boolean isEmailGranted=false
List<Permission> permissions = facebook?.userOperations()?.getUserPermissions()
String permissionString = "["
for (int i=0;i<permissions.size();i++) {
permissionString += "["+ permissions[i].getName() + ":" + permissions[i].getStatus()+"]"
if (permissions[i].getName()=="email" && permissions[i].isGranted())
isEmailGranted=true
}
permissionString += "]"
log.info("create: Facebook Permissions = " + permissionString)
def grailsWebRequest = WebUtils.retrieveGrailsWebRequest()
def flash = grailsWebRequest.flashScope
if (!isEmailGranted) {
log.warn("create: Unable to subscribe facebook user because email priviledge was not granted.")
flash.message = 'Login to Facebook failed. We must have access to your email address in order to proceed with login.'
throw new InsufficientAuthenticationException("Facebook email not accessible")
}
log.info("created: ")
String email = fbProfile.getEmail()
String firstName = fbProfile.getFirstName()
String lastName = fbProfile.getLastName()
String fullName = fbProfile.getName()
String username = firstName
String password = token.accessToken.accessToken
if (!email) {
log.error("create: Permission was granted to use facebook email but the value is null.")
flash.message = 'Login to Facebook failed. We are temporarily unable to access your email although permission has been granted'
throw new InsufficientAuthenticationException("Facebook email not accessible for unknown reason")
}
Why would I receive an empty email when permission has been granted? Is there a preferred method for handling this behavior (other than failing the authentication and making up a fake email address). Many thanks!
The documentation for the 'email' field of the 'user' object ( https://developers.facebook.com/docs/reference/api/user/ ) clarifies the expected behaviour here, which is:
"this field will not be returned if no valid email address is available"
There is a detailed explanation about different situations where an email won't be sent. Please check it out:
https://developers.facebook.com/bugs/298946933534016/
I hope it helps.
I'm using omniauth for user to signin using his Facebook and Twitter account. Everything is working fine till here, getting whatever I need and saving in my db. Now what I want is to update update user info for example: image (more specific) or name or any other thing, how should I do that, so that it's updated information appears in my app as well.
I am posting my user model code where I'm saving the user
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
if user
return user
else
registered_user = User.where(:email => auth.info.email).first
if registered_user
return registered_user
else
user = User.create(name:auth.extra.raw_info.name,provider:auth.provider,uid:auth.uid,email:auth.info.email,password:Devise.friendly_token[0,20],image:auth.info.image)
end
end
end
You can refactor your code like this:
def self.find_for_facebook_oauth(auth)
user = User.where("(uid = ? AND provider = 'facebook') OR lower(email) = ?", auth.uid, auth.info.email).first || User.new
#Here you simply update the attributes you want
user.name = auth.extra.raw_info.name
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0..20]
user.image = auth.info.image
user.save
user
end
I highly recommend you include a oauth_token and oauth_expires_at fields for further extension and usage of the Facebook Graph.
Hope this helps!
I'm using Zend_Auth with a "Database Table Authentication". What I want to do is allow the user to login with either a username or email address as the "identityColumn". How would I allow both. I'm stuck.
Extend and implement your own Auth Adapter and use query like "WHERE username = ? or email = ?" to get Auth result :)
Authenticate twice (if needed) with 2 different Zend_Auth_Adapter_DbTable objects and add some logic to determine if the login is username or email by guessing if what type of login user provided so that you save one query for most of the cases.
I know this is not the cleanest Zend_Auth implementation, but it works. The only problem comes if someone registers with an different email address as a username, but of course you can prevent this in your registration form. Hope it helps.
// if the entered value validates as an email address then use the 'email' field
// if not, use the 'username' field
$validator = new Zend_Validate_EmailAddress();
if ($validator->isValid($form->getValue('password'))) {
$identityField = 'email';
} else {
$identityField = 'username';
}
$authAdapter = new Zend_Auth_Adapter_DbTable(
$dbAdapter,
'users',
$identityField,
'password',
'SHA1(?)'
);
$authAdapter->setIdentity($form->getValue('username'))
->setCredential($form->getValue('password'));