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
Related
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
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´m playing around with the FirebaseUI-Android and have a question about what ID to use when uniquely identify users. The FirebaseUI managed the authentication right and return the IdpResponse object. This can be e.g. Facebook, Twitter, Phone and more.. This is grate thanks everyone behind this.
Because the FirebaseUser.getUid() can change when user delete/recreate his account therefore i don't want to link my users data with the FirebaseUser.getUid() token.
In the future if I decide to let user wipe there account the uid will change when user come back and all user history for that user in my system is not accessible anymore right. Also in the future if I migrate my system to someplace the uid will not be that handy to have around right?
Now I created this wrapper(code below) to create a unique ID extrapolated from the data inside the IdpResponse. Dunno really but I figure doing it this way there will never be a "id" collision unless there´s a Google2.0 e.g. Twitter2.0 :) right. And at the same time it´s easier to debunk bugs in the system because id´s are not UUID.
Is this a recommended way to handle the user id problem. I really need some feedback and pitfalls warnings about this.
#Override
public String getUserId() {
String userId;
FirebaseUser user = getInstance().getCurrentUser();
if (user.getEmail() != null)
// User sign in with E-Mail
userId = user.getEmail().replace(".", ",");
else if (user.getPhoneNumber() != null){
// User sign in with Phone
userId = user.getPhoneNumber();
}else
// User sign in with Twitter or Facebook
userId = user.getUid();
return userId;
}
What bother me most with this is the Twitter or Facebook since I still have to use the FirebaseUser.getUid(). Is the IdpResponse.getIdpToken() better to us?
As you mentioned in your post, using the uid is not the best option. If the user removes his account and than tries to create another account, another uid is generated. So in this case, he losses all data history.
The best way to identify users, is to use the email address. The email address is unique, easy to use and if want in the future, to link a Google account with a Facebook account and with a Twitter account, based on the email address, you'll be able to do id. Because Firebase does not accept . symbol in the key, i suggest you encode the email address like this:
name#email.com -> name#email,com
As you probably see, i have changed the the dot symbol . with a coma ,. To achive this i recomand you using this methods:
static String encodeUserEmail(String userEmail) {
return userEmail.replace(".", ",");
}
static String decodeUserEmail(String userEmail) {
return userEmail.replace(",", ".");
}
Hope it helps.
i am trying to integrate my app with firebase to save simple data on cloud.
Example:
user open the app and login.
user write some stuff,the data saved on cloud.
when the user will use the app again he will see his data.
i have read the docs but i coud not find any example how the
structure works between the user and the data.
user logged in , now how to save strings/object for that user?
what i tried:
user login or authenticate the user
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.addAuthStateListener(new Firebase.AuthStateListener() {
#Override
public void onAuthStateChanged(AuthData authData) {
if (authData != null) {
// user is logged in
} else {
// user is not logged in
}
}
});
now how to save under that user objects/strings?
It looks like you're using and old Android API for Firebase.
With the latest Android API there is no more need for "https://<YOUR-FIREBASE-APP>.firebaseio.com" in your code.
I would suggest to migrate, using that migration guide.
Once you have logged your user following that guide
Then you can store user information like in that documentation :
String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
mDatabase.child("users").child(userId).child("name").setValue("John");
Don't forget to change your security rule in Firebase to make sure only this user can access his own data: guide here. It's very easy and quick to do and very important for keeping your user's data private.
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.