$firebase with userid reference, init after user login best practice? - firebase

Just like firefeed, i'm storing user-meta under /users/userid.
I only need the meta for the currently logged in user, so my thinking is to grab a reference only for the logged in user. So instead of
usersRef = new Firebase(firebase/users/) && users = $firebase(usersRef)
i'm waiting until the login service sets the current user, and then created the reference based on that user's id. This is inside of a service.
var userRef = undefined;
var user = undefined;
var _setCurrentUser = function (passedUser) {
console.log(passedUser);
currentUser = passedUser;
if (!currentUser) {
userRef = new Firebase(FIREBASE_URI + 'users/' + currentUser.id);
user = $firebase(userRef);
}
};
My question is: Is this a good idea? If i don't need a reference to the entire users object, does it make sense performance-wise to specify a specific user. How so/in what way? Is there a better way to wait until we have the current user's id to create the firebase instance for the user?

Ideally, if you don't need all users, you would fetch the specific reference. Something like the following:
var app = angular.module('myApp', ['firebase']);
// a little abstraction to manage establishing a $firebaseSimpleLogin instance
app.factory('loginService', function($firebaseSimpleLogin, Firebase) {
var fb = new Firebase(URL);
var auth = $firebaseSimpleLogin(fb);
return auth;
});
// a little abstraction to reduce the deps involved in creating a $firebase object
app.factory('syncData', function($firebase, Firebase) {
return function(pathToData) {
return $firebase(new Firebase(URL).child(pathToData));
}
});
app.factory('logInAndReturnUser', function(loginService, syncData) {
return function(provider) {
// call the login service
return loginService.$login(provider)
.then(function(user) {
// resolve to a $firebase object for the specific user
return syncData('users/'+user.uid);
});
}
});
Angular-ui's ui-router is ideal for this sort of use case and I highly recommend this approach for dealing with auth. Simply set up a resolve that returns the user:
var app = angular.module('myApp', ['firebase']);
app.factory('loginService', function($firebaseSimpleLogin, Firebase) {
var fb = new Firebase(URL);
var auth = $firebaseSimpleLogin(fb);
return auth;
});
app.configure(function($stateProvider) {
$stateProvider.state('home', {
url: '/',
resolve: {
'user': function(loginService) {
// getCurrentUser returns a promise that resolves to the user object
// or null if not logged in
return loginService.$getCurrentUser();
}
},
controller: 'homeCtrl'
})
});
app.controller('homeCtrl', function(user) {
// assumes we've logged in already, that can be part of router
// processing or we could check for user === null here and send to login page
console.log('user is ' + user.uid);
});

Related

How to complete login only after functions.auth.user().onCreate is finished

I'm using firebase functions and I have a function which add new collection when user is creating. The problem is sometimes user is logged in before function is done, so user is logged in but new collection is not created yet (and then I have error message 'Missing or insufficient permissions. because a rule cannot find that collection'). How can I handle it?
Is it possible to finish login user (for example using google provider) only when all stuff from
export const createCollection = functions.auth.user().onCreate(async user => {
try {
const addLanguages = await addFirst();
const addSecondCollection = await addSecond();
async function addFirst() {
const userRef = admin.firestore().doc(`languages/${user.uid}`);
await userRef.set(
{
language: null
},
{ merge: true }
);
return 'done';
}
async function addSecond() {
// ...
}
return await Promise.all([addLanguages, addSecondCollection]);
} catch (error) {
throw new functions.https.HttpsError('unknown', error);
}
});
is finished? So google provider window is closed and user is logged in only after that? (and don't using setTimeouts etc)
AFAIK it is not possible to directly couple the two processes implied in your application:
On one hand you have the Google sign-in flow implemented in your front-end (even if there is a call to the Auth service in the back-end), and;
On the other hand you have the Cloud Function that is executed in the back-end.
The problem you encounter comes from the fact that as soon as the Google sign-in flow is successful, your user is signed in to your app and tries to read the document to be created by the Cloud Function.
In some cases (due for example to the Cloud Function cold start) this document is not yet created when the user is signed in, resulting in an error.
One possible solution would be to set a Firestore listener in your front-end to wait for this document to be created, as follows. Note that the following code only takes into account the Firestore document created by the addFirst() function, since you don't give any details on the second document to be created through addSecond().
firebase.auth().signInWithPopup(provider)
.then(function(result) {
var token = result.credential.accessToken;
var user = result.user;
//Here we know the userId then we can set a listener to the doc languages/${user.uid}
firebase.firestore().collection("languages").doc(user.uid)
.onSnapshot(function(doc) {
if(doc.exists) {
console.log("Current data: ", doc.data());
//Do whatever you want with the user doc
} else {
console.log("Language document not yet created by the Cloud Function");
}
});
}).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
var email = error.email;
var credential = error.credential;
// ...
});
As said above, in the above code we only take into account the first Firestore document created by the addFirst() function. But you probably need to wait for the two docs to be created before reading them from the front-end.
So, you may modify you CF as follows:
export const createCollection = functions.auth.user().onCreate(async user => {
try {
await addFirst();
await addSecond();
return null;
async function addFirst() {
const userRef = admin.firestore().doc(`languages/${user.uid}`);
await userRef.set(
{
language: null
},
{ merge: true }
);
}
async function addSecond() {
// ...
}
} catch (error) {
console.log(error);
return null;
}
});
Note that you don't need to use Promise.all(): the following two lines already execute the two document writes to Firestore. And, since you use async/await the second document is only written after the first one is written.
const addLanguages = await addFirst();
const addSecondCollection = await addSecond();
So you just need to set the listener on the path of the second document, and you are done!
Finally, note that doing
throw new functions.https.HttpsError('unknown', error);
in your catch block is the way you should handle errors for a Callable Cloud Function. Here, you are writing a background triggered Cloud Function, and you can just use return null;

How do I link auth users to collection in Firestore?

I'm trying to connect a user to the user collection in firestore. I'm using cloud functions, but I don't think I'm implementing it correctly.
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(() => {
console.log('user created')
exports.createUserDoc = functions.auth.user().onCreate((user) => {
console.log("hi")
const userId = user.uid;
const account = {
posts: []
}
return admin.firestore().collection("Users").doc(userId).add(account)
})
But my console.log(hi) isn't showing up. Am I approaching this correctly? Any advice helps!
Right now what i have done is when a user creates an account
i will log the login information into the database.
The document name is set to the user UID that firebase give the user.
Now you can simply request the data from the database with the user UID as
being your .doc(user.uid).
This is the full code.
var htmlEmail = document.getElementById('email').value;
var htmlPass = document.getElementById('password').value;
var htmlUser = document.getElementById('username').value.toLowerCase();
var auth = firebase.auth();
var promise = auth.createUserWithEmailAndPassword(htmlEmail, htmlPass);
// If there is any error stop the process.
promise.catch(function (error) {
var errorCode = error.code;
console.log(`GOT ERROR: ` + errorCode)
if (errorCode == 'auth/weak-password') return // password to weak. Minimal 6 characters
if (errorCode == 'auth/email-already-in-use') return // Return a email already in use error
});
// When no errors create the account
promise.then(function () {
var userUid = auth.currentUser.uid;
var db = firebase.firestore();
db.collection('users').doc(userUid).set({
email: htmlEmail,
emailVertified: false,
name: htmlUser,
online: false,
onlock: false,
password: htmlPass
});
});
Then when the user logs you can simply request the data over the user.uid.
var auth = firebase.auth();
firebase.auth().onAuthStateChanged(function (user) {
// Lay connection with the database.
var firestore = firebase.firestore();
var db = firestore.collection('users').doc(user.uid);
// Get the user data from the database.
db.get().then(function (db) {
// Catch error if exists.
promise.catch(function (error) {
// Return error
});
promise.then(function () {
// continue when success
});
});
});
There could just be there are better ways. (still learning myself).
But this does the trick for me and works very well.
There are 2 things to keep in mind !
I would recommend Firestore over the real time database as it is faster and more secure.
Make sure your database rules are set correctly, so that no one can view / leak your database information. (as you are logging users personal info). If not set correctly users will be able to view your database and even purge all data.
Hope it helps :)
If you find a better way yourself please let us know in here.
We could learn from that also !
In a simplified way you can do this, everytime a user will signup this function will create a firestore collection with the specific parameters.
signupWithEmail: async (_, { email, password, name }) => {
var user = firebase.auth().createUserWithEmailAndPassword(email,
password).then(cred => {
return
firebase.firestore().collection('USERS').doc(cred.user.uid).set({
email,
name
})
})
return { user }
}

Firebase Vue Vuefire UID not availabe in time

I'm trying to get vuefire/vue/firebase to work when there is auth and separate users. I can get it to work when I pass a UID manually...
let booksRef = db.ref('Users/' + 'SOhUKhcWzVRZmqe3AfcWMRwQR4r2' + '/Books');
But, when I try and replace the hard coded uid with one that comes from Firebase, I get a null result... It is basically not ready at the time of the call, even if the user is logged in...:
beforeCreate: function() {
var context = this;
Firebase.auth().onAuthStateChanged(function(user) {
if (user) {
currentUser = user;
context.currentUserId = user.uid;
context.currentUserEmail = user.email;
context.signedIn = true;
}
else {
context.currentUserId = null;
context.currentUserEmail = null; }
});
How can I ensure I get the UID first before I create the path to the dataset?
Thanks!
I figured this out, with the help of a GitHub example.
I'm providing the GitHub link below. But, in short, you have to do things a bit differently when using auth and UID... It's not well documented by Vuefire. You need to use a VueJS lifecycle method beforeCreate, along with a special Vuefire binding $bindAsArray.
Here's a snippet that shows the usage:
new Vue({
el: '#app',
beforeCreate: function() {
// Setup Firebase onAuthStateChanged handler
//
// https://firebase.google.com/docs/reference/js/firebase.auth.Auth
// https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onAuthStateChanged
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
this.user = user
// https://github.com/vuejs/vuefire/blob/master/src/vuefire.js#L169
this.$bindAsArray('messages', db.ref('messages/' + user.uid))
} else {
// https://firebase.google.com/docs/reference/js/firebase.auth.Auth#signInAnonymously
firebase.auth().signInAnonymously().catch(console.error)
}
}.bind(this))
},
// Initialize reactive props, bind later when user is available
data: {
user: {},
messages: []
},
See the full github example here:

Firebase: How to stop newly created user from getting logged in automatically? [duplicate]

So I have this issue where every time I add a new user account, it kicks out the current user that is already signed in. I read the firebase api and it said that "If the new account was created, the user is signed in automatically" But they never said anything else about avoiding that.
//ADD EMPLOYEES
addEmployees: function(formData){
firebase.auth().createUserWithEmailAndPassword(formData.email, formData.password).then(function(data){
console.log(data);
});
},
I'm the admin and I'm adding accounts into my site. I would like it if I can add an account without being signed out and signed into the new account. Any way i can avoid this?
Update 20161110 - original answer below
Also, check out this answer for a different approach.
Original answer
This is actually possible.
But not directly, the way to do it is to create a second auth reference and use that to create users:
var config = {apiKey: "apiKey",
authDomain: "projectId.firebaseapp.com",
databaseURL: "https://databaseName.firebaseio.com"};
var secondaryApp = firebase.initializeApp(config, "Secondary");
secondaryApp.auth().createUserWithEmailAndPassword(em, pwd).then(function(firebaseUser) {
console.log("User " + firebaseUser.uid + " created successfully!");
//I don't know if the next statement is necessary
secondaryApp.auth().signOut();
});
If you don't specify which firebase connection you use for an operation it will use the first one by default.
Source for multiple app references.
EDIT
For the actual creation of a new user, it doesn't matter that there is nobody or someone else than the admin, authenticated on the second auth reference because for creating an account all you need is the auth reference itself.
The following hasn't been tested but it is something to think about
The thing you do have to think about is writing data to firebase. Common practice is that users can edit/update their own user info so when you use the second auth reference for writing this should work. But if you have something like roles or permissions for that user make sure you write that with the auth reference that has the right permissions. In this case, the main auth is the admin and the second auth is the newly created user.
Update 20161108 - original answer below
Firebase just released its firebase-admin SDK, which allows server-side code for this and other common administrative use-cases. Read the installation instructions and then dive into the documentation on creating users.
original answer
This is currently not possible. Creating an Email+Password user automatically signs that new user in.
I just created a Firebase Function that triggers when a Firestore document is Created (with rules write-only to admin user). Then use admin.auth().createUser() to create the new user properly.
export const createUser = functions.firestore
.document('newUsers/{userId}')
.onCreate(async (snap, context) => {
const userId = context.params.userId;
const newUser = await admin.auth().createUser({
disabled: false,
displayName: snap.get('displayName'),
email: snap.get('email'),
password: snap.get('password'),
phoneNumber: snap.get('phoneNumber')
});
// You can also store the new user in another collection with extra fields
await admin.firestore().collection('users').doc(newUser.uid).set({
uid: newUser.uid,
email: newUser.email,
name: newUser.displayName,
phoneNumber: newUser.phoneNumber,
otherfield: snap.get('otherfield'),
anotherfield: snap.get('anotherfield')
});
// Delete the temp document
return admin.firestore().collection('newUsers').doc(userId).delete();
});
You can Algo use functions.https.onCall()
exports.createUser= functions.https.onCall((data, context) => {
const uid = context.auth.uid; // Authorize as you want
// ... do the same logic as above
});
calling it.
const createUser = firebase.functions().httpsCallable('createUser');
createUser({userData: data}).then(result => {
// success or error handling
});
Swift 5: Simple Solution
First store the current user in a variable called originalUser
let originalUser = Auth.auth().currentUser
Then, in the completion handler of creating a new user, use the updateCurrentUser method to restore the original user
Auth.auth().updateCurrentUser(originalUser, completion: nil)
Here is a simple solution using web SDKs.
Create a cloud function (https://firebase.google.com/docs/functions)
import admin from 'firebase-admin';
import * as functions from 'firebase-functions';
const createUser = functions.https.onCall((data) => {
return admin.auth().createUser(data)
.catch((error) => {
throw new functions.https.HttpsError('internal', error.message)
});
});
export default createUser;
Call this function from your app
import firebase from 'firebase/app';
const createUser = firebase.functions().httpsCallable('createUser');
createUser({ email, password })
.then(console.log)
.catch(console.error);
Optionally, you can set user document information using the returned uid.
createUser({ email, password })
.then(({ data: user }) => {
return database
.collection('users')
.doc(user.uid)
.set({
firstname,
lastname,
created: new Date(),
});
})
.then(console.log)
.catch(console.error);
I got André's very clever workaround working in Objective-C using the Firebase iOS SDK:
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"GoogleService-Info" ofType:#"plist"];
FIROptions *secondaryAppOptions = [[FIROptions alloc] initWithContentsOfFile:plistPath];
[FIRApp configureWithName:#"Secondary" options:secondaryAppOptions];
FIRApp *secondaryApp = [FIRApp appNamed:#"Secondary"];
FIRAuth *secondaryAppAuth = [FIRAuth authWithApp:secondaryApp];
[secondaryAppAuth createUserWithEmail:user.email
password:user.password
completion:^(FIRUser * _Nullable user, NSError * _Nullable error) {
[secondaryAppAuth signOut:nil];
}];
Update for Swift 4
I have tried a few different options to create multiple users from a single account, but this is by far the best and easiest solution.
Original answer by Nico
First Configure firebase in your AppDelegate.swift file
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
FirebaseApp.configure(name: "CreatingUsersApp", options: FirebaseApp.app()!.options)
return true
}
Add the following code to action where you are creating the accounts.
if let secondaryApp = FirebaseApp.app(name: "CreatingUsersApp") {
let secondaryAppAuth = Auth.auth(app: secondaryApp)
// Create user in secondary app.
secondaryAppAuth.createUser(withEmail: email, password: password) { (user, error) in
if error != nil {
print(error!)
} else {
//Print created users email.
print(user!.email!)
//Print current logged in users email.
print(Auth.auth().currentUser?.email ?? "default")
try! secondaryAppAuth.signOut()
}
}
}
}
You can use firebase function for add users.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const cors = require('cors')({
origin: true,
});
exports.AddUser = functions.https.onRequest(( req, res ) => {
// Grab the text parameter.
cors( req, res, () => {
let email = req.body.email;
let passwd = req.body.passwd;
let role = req.body.role;
const token = req.get('Authorization').split('Bearer ')[1];
admin.auth().verifyIdToken(token)
.then(
(decoded) => {
// return res.status(200).send( decoded )
return creatUser(decoded);
})
.catch((err) => {
return res.status(401).send(err)
});
function creatUser(user){
admin.auth().createUser({
email: email,
emailVerified: false,
password: passwd,
disabled: false
})
.then((result) => {
console.log('result',result);
return res.status(200).send(result);
}).catch((error) => {
console.log(error.message);
return res.status(400).send(error.message);
})
}
});
});
CreateUser(){
//console.log('Create User')
this.submitted = true;
if (this.myGroup.invalid) {
return;
}
let Email = this.myGroup.value.Email;
let Passwd = this.myGroup.value.Passwd;
let Role = 'myrole';
let TechNum = this.myGroup.value.TechNum;
let user = JSON.parse(localStorage.getItem('user'));
let role = user.role;
let AdminUid = user.uid;
let authToken = user.stsTokenManager.accessToken;
let httpHeaders = new HttpHeaders().set('Authorization', 'Bearer ' + authToken);
let options = { headers: httpHeaders };
let params = { email:Email,passwd:Passwd,role:Role };
this.httpClient.post('https://us-central1-myproject.cloudfunctions.net/AddUser', params, options)
.subscribe( val => {
//console.log('Response from cloud function', val );
let createdUser:any = val;
//console.log(createdUser.uid);
const userRef: AngularFirestoreDocument<any> = this.afs.doc(`users/${createdUser.uid}`);
const userUpdate = {
uid: createdUser.uid,
email: createdUser.email,
displayName: null,
photoURL: null,
emailVerified: createdUser.emailVerified,
role: Role,
TechNum:TechNum,
AccountAccess:this.AccountAccess,
UserStatus:'open',
OwnerUid:AdminUid,
OwnerUidRole:role,
RootAccountAccess:this.RootAccountAccess
}
userRef.set(userUpdate, {
merge: false
});
this.toastr.success('Success, user add','Success');
this.myGroup.reset();
this.submitted = false;
},
err => {
console.log('HTTP Error', err.error)
this.toastr.error(err.error,'Error')
},
() => console.log('HTTP request completed.')
);
}
On the web, this is due to unexpected behavior when you call createUserWithEmailAndPassword out of the registration context; e.g. inviting a new user to your app by creating a new user account.
Seems like, createUserWithEmailAndPassword method triggers a new refresh token and user cookies are updated too. (This side-effect is not documented)
Here is a workaround for Web SDK:
After creating the new user;
firebase.auth().updateCurrentUser (loggedInUser.current)
provided that you initiate loggedInUser with the original user beforehand.
Hey i had similar problem ,trying to create users through admin , as it is not possible to signUp user without signIn ,I created a work around ,adding it below with steps
Instead of signup create a node in firebase realtime db with email as key (firebase do not allow email as key so I have created a function to generate key from email and vice versa, I will attach the functions below)
Save a initial password field while saving user (can even hash it with bcrypt or something, if you prefer though it will be used one time only)
Now Once user try to login check if any node with that email (generate key from email) exist in the db and if so then match the password provided.
If the password matched delete the node and do authSignUpWithEmailandPassword with provided credentials.
User is registered successfully
//Sign In
firebaseDB.child("users").once("value", (snapshot) => {
const users = snapshot.val();
const userKey = emailToKey(data.email);
if (Object.keys(users).find((key) => key === userKey)) {
setError("user already exist");
setTimeout(() => {
setError(false);
}, 2000);
setLoading(false);
} else {
firebaseDB
.child(`users`)
.child(userKey)
.set({ email: data.email, initPassword: data.password })
.then(() => setLoading(false))
.catch(() => {
setLoading(false);
setError("Error in creating user please try again");
setTimeout(() => {
setError(false);
}, 2000);
});
}
});
//Sign Up
signUp = (data, setLoading, setError) => {
auth
.createUserWithEmailAndPassword(data.email, data.password)
.then((res) => {
const userDetails = {
email: res.user.email,
id: res.user.uid,
};
const key = emailToKey(data.email);
app
.database()
.ref(`users/${key}`)
.remove()
.then(() => {
firebaseDB.child("users").child(res.user.uid).set(userDetails);
setLoading(false);
})
.catch(() => {
setLoading(false);
setError("error while registering try again");
setTimeout(() => setError(false), 4000);
});
})
.catch((err) => {
setLoading(false);
setError(err.message);
setTimeout(() => setError(false), 4000);
});
};
//Function to create a valid firebase key from email and vice versa
const emailToKey = (email) => {
//firebase do not allow ".", "#", "$", "[", or "]"
let key = email;
key = key.replace(".", ",0,");
key = key.replace("#", ",1,");
key = key.replace("$", ",2,");
key = key.replace("[", ",3,");
key = key.replace("]", ",4,");
return key;
};
const keyToEmail = (key) => {
let email = key;
email = email.replace(",0,", ".");
email = email.replace(",1,", "#");
email = email.replace(",2,", "$");
email = email.replace(",3,", "[");
email = email.replace(",4,", "]");
return email;
};
If you want to do it in your front end create a second auth reference use it to create other users and sign out and delete that reference. If you do it this way you won't be signed out when creating a new user and you won't get the error that the default firebase app already exists.
const createOtherUser =()=>{
var config = {
//your firebase config
};
let secondaryApp = firebase.initializeApp(config, "secondary");
secondaryApp.auth().createUserWithEmailAndPassword(email, password).then((userCredential) => {
console.log(userCredential.user.uid);
}).then(secondaryApp.auth().signOut()
)
.then(secondaryApp.delete()
)
}
Update 19.05.2022 - using #angular/fire (latest available = v.7.3.0)
If you are not using firebase directly in your app, but use e.g. #angular/fire for auth purposes only, you can use the same approach as suggested earlier as follows with the #angular/fire library:
import { Auth, getAuth, createUserWithEmailAndPassword } from '#angular/fire/auth';
import { deleteApp, initializeApp } from '#angular/fire/app';
import { firebaseConfiguration } from '../config/app.config'; // <-- Your project's configuration here.
const tempApp = initializeApp(firebaseConfiguration, "tempApp");
const tempAppAuth = getAuth(tempApp);
await createUserWithEmailAndPassword(tempAppAuth, email, password)
.then(async (newUser) => {
resolve( () ==> {
// Do something, e.g. add user info to database
});
})
.catch(error => reject(error))
.finally( () => {
tempAppAuth.signOut()
.then( () => deleteApp(tempApp));
});
The Swift version:
FIRApp.configure()
// Creating a second app to create user without logging in
FIRApp.configure(withName: "CreatingUsersApp", options: FIRApp.defaultApp()!.options)
if let secondaryApp = FIRApp(named: "CreatingUsersApp") {
let secondaryAppAuth = FIRAuth(app: secondaryApp)
secondaryAppAuth?.createUser(...)
}
Here is a Swift 3 adaptaion of Jcabrera's answer :
let bundle = Bundle.main
let path = bundle.path(forResource: "GoogleService-Info", ofType: "plist")!
let options = FIROptions.init(contentsOfFile: path)
FIRApp.configure(withName: "Secondary", options: options!)
let secondary_app = FIRApp.init(named: "Secondary")
let second_auth = FIRAuth(app : secondary_app!)
second_auth?.createUser(withEmail: self.username.text!, password: self.password.text!)
{
(user,error) in
print(user!.email!)
print(FIRAuth.auth()?.currentUser?.email ?? "default")
}
If you are using Polymer and Firebase (polymerfire) see this answer: https://stackoverflow.com/a/46698801/1821603
Essentially you create a secondary <firebase-app> to handle the new user registration without affecting the current user.
Android solution (Kotlin):
1.You need FirebaseOptions BUILDER(!) for setting api key, db url, etc., and don't forget to call build() at the end
2.Make a secondary auth variable by calling FirebaseApp.initializeApp()
3.Get instance of FirebaseAuth by passing your newly created secondary auth, and do whatever you want (e.g. createUser)
// 1. you can find these in your project settings under general tab
val firebaseOptionsBuilder = FirebaseOptions.Builder()
firebaseOptionsBuilder.setApiKey("YOUR_API_KEY")
firebaseOptionsBuilder.setDatabaseUrl("YOUR_DATABASE_URL")
firebaseOptionsBuilder.setProjectId("YOUR_PROJECT_ID")
firebaseOptionsBuilder.setApplicationId("YOUR_APPLICATION_ID") //not sure if this one is needed
val firebaseOptions = firebaseOptionsBuilder.build()
// indeterminate progress dialog *ANKO*
val progressDialog = indeterminateProgressDialog(resources.getString(R.string.progressDialog_message_registering))
progressDialog.show()
// 2. second auth created by passing the context, firebase options and a string for secondary db name
val newAuth = FirebaseApp.initializeApp(this#ListActivity, firebaseOptions, Constants.secondary_db_auth)
// 3. calling the create method on our newly created auth, passed in getInstance
FirebaseAuth.getInstance(newAuth).createUserWithEmailAndPassword(email!!, password!!)
.addOnCompleteListener { it ->
if (it.isSuccessful) {
// 'it' is a Task<AuthResult>, so we can get our newly created user from result
val newUser = it.result.user
// store wanted values on your user model, e.g. email, name, phonenumber, etc.
val user = User()
user.email = email
user.name = name
user.created = Date().time
user.active = true
user.phone = phone
// set user model on /db_root/users/uid_of_created_user/, or wherever you want depending on your structure
FirebaseDatabase.getInstance().reference.child(Constants.db_users).child(newUser.uid).setValue(user)
// send newly created user email verification link
newUser.sendEmailVerification()
progressDialog.dismiss()
// sign him out
FirebaseAuth.getInstance(newAuth).signOut()
// DELETE SECONDARY AUTH! thanks, Jimmy :D
newAuth.delete()
} else {
progressDialog.dismiss()
try {
throw it.exception!!
// catch exception for already existing user (e-mail)
} catch (e: FirebaseAuthUserCollisionException) {
alert(resources.getString(R.string.exception_FirebaseAuthUserCollision), resources.getString(R.string.alertDialog_title_error)) {
okButton {
isCancelable = false
}
}.show()
}
}
}
For Android, i suggest a simpler way to do it, without having to provide api key, application id...etc by hand by just using the FirebaseOptions of the default instance.
val firebaseDefaultApp = Firebase.auth.app
val signUpAppName = firebaseDefaultApp.name + "_signUp"
val signUpApp = try {
FirebaseApp.initializeApp(
context,
firebaseDefaultApp.options,
signUpAppName
)
} catch (e: IllegalStateException) {
// IllegalStateException is throw if an app with the same name has already been initialized.
FirebaseApp.getInstance(signUpAppName)
}
// Here is the instance you can use to sign up without triggering auth state on the default Firebase.auth
val signUpFirebaseAuth = Firebase.auth(signUpApp)
How to use ?
signUpFirebaseAuth
.createUserWithEmailAndPassword(email, password)
.addOnSuccessListener {
// Optional, you can send verification email here if you need
// As soon as the sign up with sign in is over, we can sign out the current user
firebaseAuthSignUp.signOut()
}
.addOnFailureListener {
// Log
}
My solution to this question is to store the User Name/Email and password in a static class and then add a new user log out the new user and immediately log in as the admin user(id pass you saved). Works like a charm for me :D
This is a version for Kotlin:
fun createUser(mail: String, password: String) {
val opts = FirebaseOptions.fromResource(requireContext())
if (opts == null) return
val app = Firebase.initialize(requireContext(), opts, "Secondary")
FirebaseAuth.getInstance(app)
.createUserWithEmailAndPassword(mail, password)
.addOnSuccessListener {
app.delete()
doWhateverWithAccount(it)
}.addOnFailureListener {
app.delete()
showException(it)
}
}
It uses the configuration from your default Firebase application instance, just under a different name.
It also deletes the newly created instance afterwards, so you can call this multiple times without any exception about already existing Secondary application.

get UID of recently created user on Firebase

Is there a way to get the UID of a recently created user?
According to createUser() documentation, it doesn't look like it returns anything.
How would one go about obtaining this information so that we can start storing information about the user?
I know a way that could be achieved would be logging in the user upon creation. But I don't want to overwrite my existing session.
var firebaseRef = new Firebase('https://samplechat.firebaseio-demo.com');
firebaseRef.createUser({
email : "bobtony#firebase.com",
password : "correcthorsebatterystaple"
}, function(err) {
if (err) {
switch (err.code) {
case 'EMAIL_TAKEN':
// The new user account cannot be created because the email is already in use.
case 'INVALID_EMAIL':
// The specified email is not a valid email.
case default:
}
} else {
// User account created successfully!
}
});
The above answers are for old firebase.
For the ones looking for new firebase implementation :
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(function success(userData){
var uid = userData.uid; // The UID of recently created user on firebase
var displayName = userData.displayName;
var email = userData.email;
var emailVerified = userData.emailVerified;
var photoURL = userData.photoURL;
var isAnonymous = userData.isAnonymous;
var providerData = userData.providerData;
}).catch(function failure(error) {
var errorCode = error.code;
var errorMessage = error.message;
console.log(errorCode + " " + errorMessage);
});
Source : Firebase Authentication Documentation
Firebase recently released an updated JavaScript client (v2.0.5) which directly exposes the user id of the newly-created user via the second argument to the completion callback. Check out the changelog at https://www.firebase.com/docs/web/changelog.html and see below for an example:
ref.createUser({
email: '...',
password: '...'
}, function(err, user) {
if (!err) {
console.log('User created with id', user.uid);
}
});
After the user is created you can authenticate him as mentioned right above the code sample on the page that you link to:
Creates a new email / password based account using the credentials specified. After the account is created, users may be authenticated with authWithPassword().
then in the authWithPassword callback, you can access the new user's auhtData. https://www.firebase.com/docs/web/api/firebase/authwithpassword.html
I asked this question on the support forums of firebase and got this answer from Jacob. I hope this helps anyone having the same issue.
Copy and pasted from http://groups.google.com/group/firebase-talk/
All you need to do is just authenticate to a different Firebase context. You can do this via an undocumented context argument when creating a new Firebase object.
// adminRef will be used to authenticate as you admin user (note the "admin" context - also note that this can be ANY string)
var adminRef = new Firebase("https://<your-firebase>.firebaseio.com", "admin");
adminRef.authWithCustomToken("<token>", function(error, authData) {
if (error !== null) {
// now you are "logged in" as an admin user
// Let's create our user using our authenticated admin ref
adminRef.createUser({
email: <email>,
password: <password>
}, function(error) {
if (error !== null) {
// let's create a new Firebase ref with a different context ("createUser" context, although this can be ANY string)
var createUserRef = new Firebase("https://<your-firebase>.firebaseio.com", "createUser");
// and let's use that ref to authenticate and get the uid (note that our other ref will still be authenticated as an admin)
createUserRef.authWithPassword({
email: <email>,
password: <password>
}, function(error, authData) {
if (error !== null) {
// Here is the uid we are looking for
var uid = authData.uid;
}
});
}
});
}
});
Note that we will be releasing a new version of Firebase soon that does return the uid in the createUser() callback. At that point, this somewhat hacky workaround will not be needed.

Resources