In my current project, I'm registering a user with email ID and then in profile section when the user updates a phone number, I authenticate that phone number & using PhoneAuthCredetials I'm merging both Authentication methods for the same user.
Now the real pain is, My user can sign in with Phone number or Email ID but for Email ID user has to enter password & for phone number it'll need OTP.
(I Tried that, Entered phone number & password for signInWithEmailAndPassword() but not worked)
I wanted the user to log in with email or phone with a password. the way Flipkart does.
Is there any way I can manage that?
Create cloud function with following code
const functions = require('firebase-functions');
const firebase = require('firebase');
const admin = require('firebase-admin');
admin.initializeApp();
firebase.initializeApp({
//Add config for web-app here
//Required because Admin SDK doesn't include signInWithEmailAndPassword method
});
exports.signInWithPhoneAndPassword = functions.https.onCall(async (data, context) => {
const phoneNumber = data.phone;
if (phoneNumber === undefined) {
return {'s':400,'m':'Bad argument: no phone number'};
}
const user = await admin.auth().getUserByPhoneNumber(phoneNumber);
const pass = data.password;
try {
await firebase.auth().signInWithEmailAndPassword(user.email, pass);
} catch (e) {
return {'s':400,'m':'Wrong password'};
}
const token = await admin.auth().createCustomToken(user.uid, {'devClaim':true}); //developer claims, optional param
return {'s':200,'t':token};
});
On client side call this function, and if it returns object with "s"==200 use token with signInWithCustomToken (Calling a Cloud Function from Android through Firebase)
Currently, this feature does not exist.
However, there are ways you can improvise and still achieve this. Here's my suggestion:
First, when a user creates an account, you need to create a separate list on your db solely for mapping emails to phone numbers. Your db might look like this:
This way, you have a full list of emails and their linked phone numbers.
Now, at the login stage, do this:
When the user clicks the login button, check whether the user inputed an email or a phone number. You can use the Patterns class to perform this check:
If the user inputed an email, go ahead with the signInWithEmailAndPassword() approach.
If the user inputed a phone number, check the database of phone numbers in your FirebaseDatabase list and get the email from there. After getting the email, perform signInWithEmailAndPassword() and pass the email you got as well as the password the user inputed.
The downside to using this method is that it incurs an extra call (to get email from phone number) but at least, this should work.
I really hope this helps, merry coding!!
Firebase phone authentication is using OTP. This way there is no need to remember the password for a user. Once authenticated, you will be registered. The OTP code acts as a password. Still, if you want to customize the authentication method, firebase provide to customize authentication method https://firebase.google.com/docs/auth/android/custom-auth
Related
I'm making a password change page. The user will need to enter their current password to go to the password change section. But I don't know how to get current password. How can I do that?
This action is one of the sensitive actions that requires to re-authenticate the user before proceeding. You can read more about it here.
Now you should ask user to re-authenticate again, if you used any provider you can get the credential from Firebase and pass to reauthenticateWithCredential function. But in your case that used password provider, meaning using email and password to sign up users, you should show a screen to users and ask them to enter their email and password again and then use that information and re-authenticate them.
Simple example:
Let's say we showed a screen to user and got their email and password from them and then we can use this information to re-authenticate user. If you're asking what if user logged in with emailA and enter EmailB to re-authenticate? The answer is that Firebase will throw an Exception(user-mismatch), so you can ask user to enter the email that they are currently logged in with.
Future<void> reauthenticateWithCredential(String email, String password) async {
try {
final user = FirebaseAuth.instance.currentUser;
final credential = EmailAuthProvider.credential(
email: email,
password: password,
);
await user.reauthenticateWithCredential(credential);
} on Exception catch (e) {
// Handle exceptions
}
}
And to get credentials from other providers like google, is similar to log in process, you use the same code, and then get the credential and pass it to reauthenticateWithCredential function to re-authenticate user again.
Now you're ready to do any sensitive actions, you can delete user account or let them request for changing their password.
If you want to reset the password you can try this Reset Password | Firebase Authentication
Not sure you can access user's password because when you look at users in Firebase you can't see password champ.
Doing this you'll have all user's data available:
User? user = FirebaseAuth.instance.currentUser;
String userName = user!.providerData.first.displayName.toString(); // Display user's name
String userPhoto = user!.providerData.first.photoURL.toString(); // Display user's photo
user.providerData.first you'll have access user's informations but the password seems to not be available
In firebase you can access the current user's data by using FirebaseAuth.getInstance().getCurrentUser()..., I am wondering is there a way to access other Authenticated users public data by their id or email.
Accesing user data is a dangerous operation, imagine an app that allows you to change others people user name.
So in the clients you cant, unless you duplicate the user data to the RTD or the Firestore and using rules set privacy controls.
What I think you are looking for is something like the admin sdk for auth that allows to search for users using email or uid.
You can see the docs here
https://firebase.google.com/docs/auth/admin/manage-users
If you dont want to setup a server you can go all the way in the Firebase way; using Functions. Functions is a trusted enviroment like a server, so it can use the admin sdk for auth. You could create an onCall function for doing whatever you want.
If you want to only search users, please consider having a searchable version of the user data on any database, if you are looking for an admin type of feature then Functions onCall is what you need.
You will probably want to set admin privileges using customs claims
https://firebase.google.com/docs/auth/admin/manage-users
exports.userCreationListener = functions.auth.user().onCreate(user => {
const admins = {
"first#admin.com": true
};
const email = user.email;
if (!admins[email]) {
return false;
}
const uid = user.uid;
return admin.auth().setCustomUserClaims(uid, {superAdmin: true}).then(
()=>admin.database().ref(`users/${uid}`).set(true)).catch(error=>{
console.log("SUPER_ADMIN_UPDATE_ERROR", error);
return false;
});
});
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
// The user's ID, unique to the Firebase project. Do NOT use this value to
// authenticate with your backend server, if you have one. Use
// FirebaseUser.getIdToken() instead.
String uid = user.getUid();
}
Read guide https://firebase.google.com/docs/database/admin/retrieve-data
I am making an android chat application using firebase. So far I have made a common group chat app. Now I want to make it an individual chat app, which will have a Users list and when we select a person from that list we can chat individually with him/her. However I am not able to get this Users list from Firebase. I have kept Google Sign in and Email sign in options in the Firebase Auth UI. Any help would be appreciated
If you need to lookup users by uid, email or phoneNumber, you can use the Admin SDK to do so:
https://firebase.google.com/docs/auth/admin/manage-users
You also even have the ability to download all your users:
https://firebase.google.com/docs/auth/admin/manage-users#list_all_users
You would need to do that from a Node.js backend server or via HTTP endpoints with Firebase Functions.
In addition the Admin SDK allows you to set custom user attributes which could be helpful if you want to create different user groups:
https://firebase.google.com/docs/auth/admin/custom-claims
admin.auth().setCustomUserClaims(uid, {groupId: '1234'})
The Firebase Admin SDK allows retrieving the entire list of users in batches:
function listAllUsers(nextPageToken) {
// List batch of users, 1000 at a time.
admin.auth().listUsers(1000, nextPageToken)
.then(function(listUsersResult) {
listUsersResult.users.forEach(function(userRecord) {
console.log('user', userRecord.toJSON());
});
if (listUsersResult.pageToken) {
// List next batch of users.
listAllUsers(listUsersResult.pageToken);
}
})
.catch(function(error) {
console.log('Error listing users:', error);
});
}
// Start listing users from the beginning, 1000 at a time.
listAllUsers();
Note: This API is currently only available for the Admin Node.js SDK.
via https://firebase.google.com/docs/auth/admin/manage-users
As pointed out by #Sam earlier, you can fetch details from Firebase DB. So every time a user signs up, add his FirebaseUser details (preferably his UID, under which you store his other details if required) to the DB. Then simply put a listener on the Database in your next activity, and you can fetch a list of all registered users.
const allUsers: firebase.auth.UserRecord[] = [];
const listAllUsers = async (nextPageToken?: string) => {
const res = await firebase.auth().listUsers(1000, nextPageToken);
allUsers.push(...res.users);
if (res.pageToken) {
await listAllUsers(res.pageToken);
}
};
await listAllUsers();
console.log(allUsers)
You cannot retrieve the data of all authenticated user from Firebase Authentication, however you can only get the current user.
In Order to get the data of registered user you need to store it into database and then retrieve the whole array, or you can just keep the authentication flag which can be set or reset if the user is registered in your all-user table and vice versa.
As mentioned by #Jason you can try Admin SDK as it is mentioned in the documentation that listAllUsers() can retrieve batch of user data.
The detailed explanation can be found IN THIS THREAD.
If you want to view a list of users that has registered thru Firebase Auth, you may view them in https://console.firebase.google.com/ then go to your project and select authentication, in the Users list is all the users that have registered thru Firebase Auth.
I am developing Android app using Firebase. Because of that, I want to use Firebase Auth. I have following requirements:
Register/Log in using Facebook
Register/Log in using Email/Password
Register/Log in using Phone Number/Password
The first two are OK, I followed basic tutorials. However, Phone Number / Password is the problem here. Firebase supports only Phone Number/SMS Token for this (its called Phone Auth), but there is no mention about my case. I do not want to hack Firebase and use its realtime database instead of Auth 'database'. Is there any better way to achieve this?
Thank you.
If you have both email and phone of your user and you can use Admin SDK, then perhaps you could exchange users phone number to his email and login with email and password in the background.
Something like this (node.js)
admin.auth().getUserByPhoneNumber(phoneNumber)
.then(user => {
firebase.auth().signInWithEmailAndPassword(user.email, password);
});
Firebase phone authentication is using OTP(one time password). This way there is no hassle for the user to remember the password. Once authenticated, you will be registered. The sms code acts as a password. But that is for one time. Usually , users prefer such behaviour in which you dont have to remember the passwords. If you are still looking for the way you want, see this link and create a custom authentication method.
https://firebase.google.com/docs/auth/android/custom-auth
I had a similar problem -
I combined firebase auth(email + password) with (phone+otp) to get phone+password auth -
https://medium.com/#shivampesitbng/firebase-phone-password-auth-in-vue-b94f15b8fb3d
Use Fake Email:
Well, Firebase doesn't support sign in with mobile number and password but it supports email and password. So you can create a fake email with your mobile number.
Ie: 78******69#yourdomain.com
Also, you can create a complete Authentication system using it.
Registration:
Input user mobile and password and proceed to the next page.
Now use Firebase Phone Auth (OTP) to createUser. If process success, link fake email, password credentials in background.
AuthCredential credential = EmailAuthProvider.getCredential(email, password);
auth.getCurrentUser().linkWithCredential(credential);
Login:
Input mobile and password to login. Convert the mobile in fake email and then signInWithEmailAndPassword().
Forget Password:
Redirect the user to a new Page and user Phone Auth to verify the user. If successful, input a new password and change the password of the Email Auth.
Question says it all. In Firebase, how do I confirm email when a user creates an account, or, for that matter, do password reset via email.
I could ask more broadly: is there any way to send emails out from Firebase? E.g. notifications, etc. This isn't the kind of thing you would usually do client-side.
Update
Note that this was never a very secure way of handling email verification, and since Firebase now supports email verification, it should probably be used instead.
Original answer
I solved the email verification using the password reset feature.
On account creation I give the user a temporary (randomly generated) password. I then trigger a password reset which will send an email to the user with a link. The link will allow the user to set a new password.
To generate a random password you can use code similar to this:
function () {
var possibleChars = ['abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?_-'];
var password = '';
for(var i = 0; i < 16; i += 1) {
password += possibleChars[Math.floor(Math.random() * possibleChars.length)];
}
return password;
}
Note that this is happening on the client, so a malicious user could tamper with your logic.
This would need to be done outside of firebase. I store users at /users/ and keep a status on them (PENDING, ACTIVE, DELETED). I have a small service that monitors users of a PENDING status and sends out a confirmation email. Which has a link to a webservice I've created to update the user status to ACTIVE.
[Engineer at Firebase - Update 2014-01-27]
Firebase Simple Login now supports password resets for email / password authentication.
Each of the Simple Login client libraries has been given a new method for generating password reset emails for the specified email address - sendPasswordResetEmail() on the Web and Android, and sendPasswordResetForEmail() on iOS.
This e-mail will contain a temporary token that the user may use to log into their account and update their credentials. This token will expire after 24 hours or when the user changes their password, whichever occurs first.
Also note that Firebase Simple Login enables full configuration of the email template as well as the sending address (including whitelabel email from your domain for paid accounts).
To get access to this feature, you'll need to update your client library to a version of v1.2.0 or greater. To grab the latest version, check out https://www.firebase.com/docs/downloads.html.
Also, check out https://www.firebase.com/docs/security/simple-login-email-password.html for the latest Firebase Simple Login - Web Client docs.
As at 2016 July, you might not have to use the reset link etc. Just use the sendEmailVerification() and applyActionCode functions:
In short, below is basically how you'll approach this, in AngularJS:
// thecontroller.js
$scope.sendVerifyEmail = function() {
console.log('Email sent, whaaaaam!');
currentAuth.sendEmailVerification();
}
// where currentAuth came from something like this:
// routerconfig
....
templateUrl: 'bla.html',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn() // this throws an AUTH_REQUIRED broadcast
}]
}
...
// intercept the broadcast like so if you want:
....
$rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
if (error === "AUTH_REQUIRED") {
$state.go('login', { toWhere: toState });
}
});
....
// So user receives the email. How do you process the `oobCode` that returns?
// You may do something like this:
// catch the url with its mode and oobCode
.state('emailVerify', {
url: '/verify-email?mode&oobCode',
templateUrl: 'auth/verify-email.html',
controller: 'emailVerifyController',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn()
}]
}
})
// Then digest like so where each term is what they sound like:
.controller('emailVerifyController', ['$scope', '$stateParams', 'currentAuth', 'DatabaseRef',
function($scope, $stateParams, currentAuth, DatabaseRef) {
console.log(currentAuth);
$scope.doVerify = function() {
firebase.auth()
.applyActionCode($stateParams.oobCode)
.then(function(data) {
// change emailVerified for logged in User
console.log('Verification happened');
})
.catch(function(error) {
$scope.error = error.message;
console.log(error.message, error.reason)
})
};
}
])
And ooh, with the above approach, I do not think there's any need keeping the verification of your user's email in your user data area. The applyActionCode changes the emailVerified to true from false.
Email verification is important when users sign in with the local account. However, for many social authentications, the incoming emailVerified will be true already.
Explained more in the article Email Verification with Firebase 3.0 SDK
What I did to work around this was use Zapier which has a built in API for firebase. It checks a location for added child elements. Then it takes the mail address and a verification url from the data of new nodes and sends them forwards. The url points back to my angular app, which sets the user email as verified.
As I host my app files in firebase, I don't need have to take care of any servers or processes doing polling in the background.
There is a delay, but as I don't block users before verifying mails it's ok. Zapier has a free tier and since I don't have much traffic it's a decent workaround for time being.
The new Firebase SDK v3 appears to support email address verification, see here (put your own project id in the link) but it doesn't appear to be documented yet.
I have asked the question on SO here
See #SamQuayle's answer there with this link to the official docs.
As noted by various others Firebase does now support account related emails but even better, as of 10 days ago or so it also supports sending any kind of email via Firebase Functions. Lots of details in the docs and example code here.
I used following code to check the email verification after creating new account.
let firAuth = FIRAuth.auth()
firAuth?.addAuthStateDidChangeListener { auth, user in
if let loggedUser = user {
if loggedUser.emailVerified == false {
loggedUser.sendEmailVerificationWithCompletion({ (error) in
print("error:\(error)")
})
}
else {
print(loggedUser.email)
}
} else {
// No user is signed in.
print("No user is signed in.")
}
}
I used MandrillApp. You can create an API key that only allows sending of a template. This way even thought your key is exposed it can't really be abused unless someone wants to fire off tonnes of welcome emails for you.
That was a hack to get myself off the ground. I'm now enabling CORS from a EC2 that uses the token to verify that the user exists before extending them a welcome via SES.