How to create new account when I'm already signed in [duplicate] - android
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.
Related
How to query user pool from cognito with lambda functions using Amplify-android AWS
I have this function signature on schema.graphql, can I used it in order to call to lambda function that retrieve user list from Cognito server? type Query { echo(msg: String): String #function(name: "getUsers-${env}") } How can I call it from Android ? Do I need Apollo ? Does Amplify library it's enough ?
Basically you can't query users from Cognito Amazon server directly using the schema. In the Android application you must create and use the following Amplify plugins, you can read more about it from here: https://docs.amplify.aws/start/q/integration/android You must create lambda function as describe here: const AWS = require('aws-sdk'); const cognito = new AWS.CognitoIdentityServiceProvider({apiVersion: '2016-04-18', region: 'eu-central-1'}); exports.handler = async (event) => { // TODO implement let users = []; let roles = ['admin', 'user' ]; try { // (let i=0, len=roles.length; i<len; i++) //{ //const role = roles[i]; let more = true; let nextToken = ''; while (more) { let params = { UserPoolId: "your pool id", //GroupName: role, Limit: 60 }; if (nextToken !== '') { params.NextToken = nextToken; } const rawUsers = await cognito.listUsers(params).promise(); const mapUsers = rawUsers.Users.map(user => { let atts = {}; for (const att of user.Attributes) { atts[att.Name] = att.Value; } return { username: user.Username, name: atts.hasOwnProperty('name') ? atts.name : '', email: atts.hasOwnProperty('email') ? atts.email : '', status: user.UserStatus, //role: role }; }); users= users.concat(mapUsers); if (rawUsers.hasOwnProperty('NextToken')) { nextToken = rawUsers.NextToken; } else { more = false; } } // } const response = { statusCode: 200, // Uncomment below to enable CORS requests // headers: { // "Access-Control-Allow-Origin": "*" // }, body: JSON.stringify(users), }; return response; } catch(e) { const response = { statusCode: 500, // Uncomment below to enable CORS requests // headers: { // "Access-Control-Allow-Origin": "*" // }, body: e, }; return response; } }; Then create REST api: Use the terminal Amplify CLI commands and connect it to the lambda function that was created including "Authenticated users only". Run: amplify add api C:\DOV_AWS>amplify api add ? Please select from one of the below mentioned services: REST ? Provide a friendly name for your resource to be used as a label for this category in the project: users ? Provide a path (e.g., /book/{isbn}): C:\DOV_AWS>amplify api add ? Please select from one of the below mentioned services: REST ? Provide a friendly name for your resource to be used as a label for this category in the project: DOV ? Provide a path (e.g., /book/{isbn}): /users ? Choose a Lambda source Use a Lambda function already added in the current Amplify projec t ? Choose the Lambda function to invoke by this path getUsers ? Restrict API access Yes ? Who should have access? Authenticated users only ? What kind of access do you want for Authenticated users? create, read, update, delete ? Do you want to add another path? No Successfully added resource DOV locally Use the amplify push command: amplify push In order to update the API on the cloud. Run the following code in your app in order to fetch the users. RestOptions options = RestOptions.builder() .addPath("/users") .build(); Amplify.API.get("Users", options, response -> Log.i("MyAmplifyApp", " ! ! ! ! ! Data Respond ! ! ! ! !" + response.getData().asString()), error -> Log.e("MyAmplifyApp", "GET failed", error) ); You must add permission rule for Cognito server in the lambda function in order to fetch the user data. The authentication method will include IAM rule
Script for making firebase user to user notifications
(Sorry for bad English) I'm looking for a way to make user to user notifications in Android. The system have to catch a new child event in the Database, read the data and send the notification to destination. The struct of the DB is this: notificationRequests $pushid message: "You have a new request! Open the app" userId: "sadbijasuobru112u4124u21b" //user destination id By doing some researches in the web I've found the possibility to use topic messages. So, i've added this in my LoginActivity befor calling the MainActivity: FirebaseMessaging.getInstance().subscribeToTopic("users_topic$uid") .addOnCompleteListener { Log.d("LoginActivity", "User registered") } The code works. I can send notifications from the console Like I said before, i need automatic messages. I've found this code on the web, but it doesn't work. var firebase = require('firebase-admin'); var request = require('request'); var API_KEY = "Firebase Cloud Messaging Server API key" // Fetch the service account key JSON file contents var serviceAccount = require("./serviceAccountKey.json"); // Initialize the app with a service account, granting admin privileges firebase.initializeApp({ credential: firebase.credential.cert(serviceAccount), databaseURL: "https://appname.firebaseio.com/" }); ref = firebase.database().ref(); function listenForNotificationRequests() { var requests = ref.child('notificationRequests'); requests.on('child_added', (requestSnapshot) => { var request = requestSnapshot.val(); sendNotificationToUser( request.userId, request.message, () => { requestSnapshot.ref.remove(); } ); }, (error) => { console.error(error); }); } function sendNotificationToUser(userID, message, onSuccess) { request({ url: 'https://fcm.googleapis.com/fcm/send', method: 'POST', headers: { 'Content-Type' :' application/json', 'Authorization': 'key='+API_KEY }, body: JSON.stringify({ notification: { title: message }, to : '/topics/users_topic'+userID }) }, (error, response, body) => { if (error) { console.error(error); } else if (response.statusCode >= 400) { console.error('HTTP Error: '+response.statusCode+' - '+response.statusMessage); } else { onSuccess(); } }); } // start listening listenForNotificationRequests(); I've implemented this code in the index.js for deployng. I've also write the entire file instead of requiring it, but it's always the same. const functions = require('firebase-functions'); exports.sendNotifications = functions.https.onRequest((request, response) => { require('./sendNotifications.js') }) Any suggestions? Thanks for the kelp! EDIT Does this need a billing account configurated? If yes, how can i make it with the free plan?
Does this need a billing account configurated? If yes, how can i make it with the free plan? See https://firebase.google.com/support/faq#functions-runtime, but in short: from Node 10 you will need to enter billing information to use Cloud Functions. You can use Node 8 until early next year without entering billing information. Note that entering billing information does not necessarily mean you'll have to pay, as Cloud Functions has a pretty significant free tier.
The problem was that I was calling an external site. I solved it doing this: const functions = require('firebase-functions'); var firebase = require('firebase-admin'); // Fetch the service account key JSON file contents var serviceAccount = require("./serviceAccountKey.json"); // Initialize the app with a service account, granting admin privileges firebase.initializeApp({ credential: firebase.credential.cert(serviceAccount), databaseURL: "https://appname.firebaseio.com/" }); exports.sendNotifications = functions.database.ref('/notificationRequest/{pushId}') .onCreate( (change, context) => { var uid = change.child('userId').val() var notificationMessage = change.child('message').val() var userTopic = 'users_topic'+uid var payload = { data: { message: notificationMessage } }; var options = { priority: 'high', timeToLive: 60 * 60 * 24, collapseKey: 'notification' }; firebase.messaging().sendToTopic(userTopic, payload, options) // eslint-disable-next-line promise/always-return .then((response) => { console.log('Done', response); }) .catch((error) => { console.log('Error: ', error); }); return change.ref.remove(); });
Firebase Trigger Razorpay Intergration for Android
I am creating an App Where user can buy coins and for that I have been trying to integrate Razorpay into my Android App since a long time now. Razorpay can directly be used in Android. It sends Success or Failure results for payment and I can act accordingly (adding points to database in this case). But the problem with this approach is that I have to write points (after success) to database from the app. Which means I have to give write access for points node to user app which is not a good idea. So I wanted to use Razorpay with Firebase Cloud Functions and searching for a long time I came across this tutorial which is for web. I am quite new to Cloud Functions and hence wanted a little help for Android. Here is the Index.js code but For Web const functions = require("firebase-functions"); var express = require("express"); var cors = require("cors"); var request = require("request"); const crypto = require("crypto"); const key = "----insert yout key here----"; const key_secret = "----- insert key secret here ----"; var app = express(); app.use(cors({ origin: true })); app.post("/", (req, res) => { const amount = req.body.amount; //Allow Api Calls from local server const allowedOrigins = [ "http://127.0.0.1:8080", "http://localhost:8080", "https://-------YourFirebaseApp-----.firebaseapp.com/" ]; const origin = req.headers.origin; if (allowedOrigins.indexOf(origin) > -1) { res.setHeader("Access-Control-Allow-Origin", origin); } var options = { method: "POST", url: "https://api.razorpay.com/v1/orders", headers: { //There should be space after Basic else you get a BAD REQUEST error Authorization: "Basic " + new Buffer(key + ":" + key_secret).toString("base64") }, form: { amount: amount, currency: "INR", receipt: "----- create a order in firestore and pass order_unique id here ---", payment_capture: 1 } }; request(options, function(error, response, body) { if (error) throw new Error(error); res.send(body); }); }); app.post("/confirmPayment", (req, res) => { const order = req.body; const text = order.razorpay_order_id + "|" + order.razorpay_payment_id; var signature = crypto .createHmac("sha256", key_secret) .update(text) .digest("hex"); if (signature === order.razorpay_signature) { console.log("PAYMENT SUCCESSFULL"); res.send("PAYMENT SUCCESSFULL"); } else { res.send("something went wrong!"); res.end(); } }); exports.paymentApi = functions.https.onRequest(app);
I think this will help you. In my case, I am accessing items(Array of Product IDs) from the user's cart and reading the current price of the items then passing it as an argument to SendOrderId function which will return an OrderId to proceed. The important thing to keep in mind is that you must have added razorpay in your dependencies inside package.json. You can do that by simply running npm i razorpay inside your functions folder (Which include index.js) which will automatically add the dependency to your project const functions = require("firebase-functions"); const admin = require('firebase-admin'); const Razorpay = require('razorpay') const razorpay = new Razorpay({ key_id: 'Your_razorpay_key_id', key_secret: 'your_secret' }) admin.initializeApp(); function SendOrderId(amountData, response) { var options = { amount: amountData, // amount in the smallest currency unit currency: "INR", }; razorpay.orders.create(options, function(err, order) { console.log(order); response.send(order); }); } exports.getOrderId = functions.https.onRequest((req, res) => { return admin.firestore().collection('Users').doc(req.query.uid).get().then(queryResult => { console.log(queryResult.data().Cart); admin.firestore().collectionGroup("Products").where('ProductId', 'in', queryResult.data().Cart).get().then(result => { var amount = 0; result.forEach(element => { amount += element.data().price; }); SendOrderId(amount * 100, res); }) }) });
React native firebase creating user then adding additional data to realtime database
I am creating an app that allows users to register themselves. Using react-native and firebase works, the are registered and are logged in. Even the additional data is stored in the realtime database (I checked it). But I am getting a message saying "creating user failed" (it is one of the messages I have setup). This is the code I use to create users and add additional data to the realtime database: firebase.auth().createUserWithEmailAndPassword(email, password) .then((user) => { firebase.database().ref('users/' + user.uid).set({ firstName: firstName, lastName: lastName, email: email, code: code }) }) .then(user => loginUserSuccess(dispatch, user)) .catch((error) => { createUserFail(dispatch) console.log(error); }); I also checked the debugger in android studio (don't know about ios yet) and saw the following comment: TypeError: undefined is not an object (evaluating 'user.uid') Still everything is saved, but the error message was shown. What am I doing wrong?
I know this is a year old but I ran into the same issue and here's a more direct solution for anyone running into the same issue. When you create a user the user object is a part of the Firebase response not the response itself. So just prepend "res" to your original code like this: firebase.auth().createUserWithEmailAndPassword(email, password) .then((res) => { firebase.database().ref('users/' + res.user.uid).set({ firstName: firstName, lastName: lastName, email: email, code: code }) })
Ok, finally I got it working. What I did was, after the first then, checking for the currentuser (because the user will be loggedin automatically), then getting the uid and using that: if (firebase.auth().currentUser) { userId = firebase.auth().currentUser.uid; if (userId) { firebase.database().ref('users/' + userId).set({ firstName: firstName, lastName: lastName, email: email, code: code }) } } This works.
firebase.auth().createUserWithEmailAndPassword(email, password).then((user)=>{ if (firebase.auth().currentUser) { userId = firebase.auth().currentUser.uid; if (userId) { firebase.database().ref('users/' + userId).set({ firstname:firstname, lastname:lastname, email:email, password:password, town:town, addInterest:addInterest, photoUrl:false, emailVerified:false, uid:userId, status:true, online:true }) } } }).catch(function(error) { // Handle Errors here. var errorCode = error.code; var errorMessage = error.message; console.log('Register!'); console.log(error); }) Full Code so easy to use. 100% work!
You didn't say if you were using this in the context of an action creator but if you did, here is another possible solution. Let's make it more interesting, its an app for adding new employees: export const employeeCreate = ({ name, phone, shift }) => { const { currentUser } = firebase.auth(); return () => { firebase .database() .ref(`/users/${currentUser.uid}/employees`) // add a .then() to ensure after employee is created // we want to navigate them back to employee list screen .push({ name, phone, shift }) .then(() => Actions.pop()); }; }; The Actions would be imported from react-native-router-flux like so: import firebase from 'firebase'; import { Actions } from 'react-native-router-flux';
Sign Up user from already logged in user in firebase will change the current user to newly created user [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.