I am developing the app which has grouping function.
Now I have the problem about adding new member in group.
Like Slack, in group creating onboarding flow user can decide group name and add members which don't use the app yet.
As adding members function, I want to use inviting mail link using firebase dynamic links.
Data structure is below
User
- id
- name
- email
Group
- id
- groupName
- members[]
Group's members array has user id.
But when someone creates new group, it is possible that new users don't register the app yet.
So they don't have user id property in the app.
How do I fix this problem?
When someone creates new group, should I develop sign up functions new user using Firebase auth? This means then new member has automatically user id, and adding those to members property.
Or should group member array have mail address instead of user id.
Please tell me. I'm happy with Swift or JavaScript you will teach me.
Thank you.
UPDATE
After reading your comment I would propose another approach.
When the Group creator user adds users to a group, if a user does not already exists you could, from the front-end, call a Callable Cloud Function (CF) that creates a temporary Firestore document in a specific collection. The ID of this document will be the (future) userId.
Then, still in this same Cloud Function, you send an email to the email address (you need to generate yourself the email, for example with the email extension) with a link containing the userId as query string value.
Example of code for this first CF:
exports.provisionNewAccount = functions
.https.onCall(async (data, context) => {
try {
// You can check that the caller is authenticated
// if (context.auth.uid) {execute the rest of the code} else {throw an error}
// New user email
const userEmail = data.email;
// Generate the new user docID
const fakeDocRef = admin.firestore().collection('_').doc();
const requestId = fakeDocRef.id;
// Create the doc in a specific collection
await admin.firestore().collection('usersCreationRequests').doc(requestId).set({ email: userEmail, treated: false });
// Generate the link to include in the email
const linkURL = 'https://your.app/register.html?requestId=' + requestId
// Send the email by creating a doc in the Extension collection
await db
.collection("emails")
.add({
to: userEmail,
message: {
subject: "....",
html: `Click to create your account` // adapt the html to add some text
},
});
return {result: 'OK'}
} catch (error) {
console.log(JSON.stringify(error));
throw new functions.https.HttpsError('internal', JSON.stringify(error));
}
});
You call it as explained here, by passing the future user's email.
When the email recipient clicks on the link, you open a specific page of your web app that shows a set of fields for the future user to enter his password, display name etc. Then on clicking on a sign-in button in this page you call a Callable Cloud Function passing it the Firestore document ID plus the field values (you get the document ID from the query string).
As shown below, this Cloud Function creates the user in the Authentication service (using the Admin SDK) and flag the Firestore document as treated. Upon getting back the Cloud Function result in the web app you authenticate the user (you have his email and password, since he/she entered it in the form).
exports.createNewAccount = functions
.https.onCall(async (data, context) => {
try {
const userEmail = data.email;
const userId = data.userId;
const userPassword = data.password;
const userDisplayName = data.displayName;
// Fetch the user doc created in the first CF
const snapshot = await admin.firestore().collection('usersCreationRequests').doc(userId).get();
const treated = snapshot.get('treated');
const email = snapshot.get('email');
if (!treated && userEmail === email) {
const createUserPayload = {
email,
emailVerified: false,
password: userPassword,
displayName: userDisplayName
};
const userRecord = await admin.auth().createUser(createUserPayload);
return { result: 'OK' }
} else {
return { result: 'User already created' }
}
} catch (error) {
console.log(JSON.stringify(error));
throw new functions.https.HttpsError('internal', JSON.stringify(error));
}
});
I’m actually using this exact approach for a B2B collaborative web app in which users can invite new users by email.
INITIAL ANSWER
(Totally different from the update)
So they don't have user id property in the app… How do I fix this
problem? When someone creates new group, should I develop sign up
functions new user using Firebase auth?
You can use the Anonymous Authentication mode, it exactly corresponds to your needs:
You can use Firebase Authentication to create and use temporary
anonymous accounts to authenticate with Firebase. These temporary
anonymous accounts can be used to allow users who haven't yet signed
up to your app to work with data protected by security rules. If an
anonymous user decides to sign up to your app, you can link their
sign-in credentials to the anonymous account so that they can continue
to work with their protected data in future sessions.
When signing-in with Anonymous Authentication a userId (uid) will be created and later you will be able to convert an anonymous account to a permanent account
I always use userId to achive this kind of feature, you can use anonymous authentication to get userId after user click invite link, Then if needed unlock more feature with furter authentication(add more provider).
If you only using mail address without authentication, It's hard to write rules for prevent user access unwanted data, Like anyone knew your email are able to access your account.
Related
After a long research on firebase-auth with email and password, I found that we can't give more than two fields (email and password).
In my assignment, they supposed to give three input fields (full name, email and password).
I have completed my assignment only with two input fileds (email and password) but they also want to store full-name in firebase.
My assignment is given bellow -
So, Is it possible to also store "full name" in firebase, If so then how ?
I could describe this question in another way, but I just tell you the truth.
Please Help Me !
Firebase Auth object has a displayName property which you use to store user's name. However, if you are using Client SDK then you would have to create the user first and then update the name. This can be done in a single step if you use Admin SDK with Cloud functions or a server.
import { useAuth } from "firebase/auth"
const auth = getAuth();
const createNewUser = async () => {
const { user } = await createUserWithEmailAndPassword(auth, email, password)
await updateProfile(user, { displayName: "Jane Q. User" })
console.log('New user', user.uid)
}
If the full name consists of a first name and a last name, then you can add a - or any symbol between them e.g. first-last in displayName. Then you can read the name as shown below:
const { displayName } = auth.currentUser
const [firstName, lastName] = displayName.split("-")
If you need to access the data from a server environment or any user management page, then it'll be best to store details of users in a database answered by #TarikHuber.
You have basicaly two options for doing that:
as mentioned in the comments you could use the database to store additional data for each user uid
use customClaims to store such additional data there
I would recommend the first one for more data if you need to store a lot of data and if you have less you could use the customClaims. They are limited in size so be carefull how much you save inside.
I have a scenario that requires checking an entered password against the user's firebase password before the user does an irreversible task. This is different from creating an account or signing in. How can you check against a firebase password? It doesn't look like there's a password property in firebase.auth().currentUser.
Update:
The user must verify their password and the Delete button will run a function to check it. If it matches the firebase password, the Delete button will succeed in triggering a pretty modal to pop up.
I would suggest you to store the user password somewhere if you need to check against it at some point.
Instead of storing it inside your database (which wouldn't be safe) I would personally store it on user's device using UserDefaults so that you can access it easily whenever you need to perform your sensible tasks.
Update:
Another possibility would be using the reauthenticateWithCredential method. If the method return success then, perform your sensitive task. If it fails, ask your user to type the correct password.
As per your request, this is how you would reauthenticate the user using his email & password :
// First you get your current user using Auth :
let currentUser = Auth.auth()?.currentUser
// Then you build up your credential using the current user's current email and password :
let credential = EmailAuthProvider.credential(withEmail: email, password: password)
// use the reauthenticate method using the credential :
currentUser?.reauthenticate(with: credential, completion: { (error) in
guard error == nil else {
return
}
// If there is no error, you're good to go
// ...Do something interesting here
})
You can find some more explanation inside the Firebase documentation here : https://firebase.google.com/docs/auth/ios/manage-users
I'm trying to update/add data on firebase. I used the Facebook login and I want to use the UserID as a key for the new data aded.
(check pict below)
The userID that I want to use it:
I want to replace that key with the userID:
fblogin(){
this.facebook.login(['email'])
.then(res=> {
const fc = firebase.auth.FacebookAuthProvider.credential(res.authResponse.accessToken);
firebase.auth().signInWithCredential(fc)
.then(fs => {
this.facebook.api('me?fields=id,name,email,first_name,picture.width(720).height(720).as(picture_large)', []).then(profile => {
this.newuser = {name: profile['first_name'] ,email: profile['email'],picture: profile['picture_large']['data']['url'],phone:''}
this.navCtrl.push(HomePage);
console.log(fs.uid);
this.db.list('/users/'+ fs.uid).update(this.newuser);
});
I got this error in compilation:
supplied parameters do not matchany signature of call target
In this line: this.db.list('/users/'+ fs.uid).update(this.newuser);
Any help?
The FB error looks correct. You cant update on the uid as the user has been saved with a unique FB id
You do not show the code that created the users record in the database, but what i think you want to do is set and object when you first save the users record. However this could be an issue because the user could be saved before the return of the uid. I cant tell with your code snippet. Regardless, I will write the code that i think will work if the users/ record is created at the time that of registration.
The service
async signupUser(email: string, password: string) {
try {
const result = await this.afA.auth.createUserWithEmailAndPassword(email, password);
return result;
} catch (err) {
console.log('error', err);
}
}
So this initially creates a user without facebook, The key here is that the users FB uid was created and is held in the returned result
The component
this.authData.signupUser(email,password).then(userData => {
console.log(userData) // <- this is result
}
Then we create a record in FB with the uid returned
this.db.object(`users/${userData.uid}/`).set(data);
.set(data) is whatever data you want to save in the users/uid namespace.
So basically you need to create that user table with its uid namespace when the user first registers. Then you can update the user with the uid returned from the facebook fs.uid
With your current code you could find the user based on the email ( because the email should be unique to all users) and then update ...
with lodash is it just
let foundUser = find(this.db.list('users'),{ 'email' : fs.email }
// and then update based on the object key
this.db.list('/users/'+ Object.keys(foundUser)).update(this.newuser);
i fixed the problem by using:
this.db.object('/users/'+ fs.uid).update(this.newuser);
instead of :
this.db.list('/users/'+ fs.uid).update(this.newuser);
And it works correctly !
Thanks all for help.
As part of my studies I need to develop web-app (javasript language) Where we work with firebase realtime database.
currently inside the database,I have a tree of users objects that representing all the users who registered to the system. And what I'm trying to do is a simple user login function.
After the user entered his username and his password, I created an array to enter the entire user tree from a database. The problem is that when im calling the function from the Firebase it's not enough to ended.. and what happens is that the array remains empty and you can not verify that the user is registered on the system.
now I have used a temporary solution that Im using setTimeout function,I understand that this is wrong programming, and also i do not want the user to wait 2 seconds every time he wants to login to the system.
Can someone please help me? how to do it right without the setTimeout function?
I want that the function of the Firebase ends so only then start with the Authentication process.
Here is the code I wrote so far,
var correntUser;
var userlist = [];
var usersRef = database.ref('users');
// Query that inserts all users keys and names to an array.
usersRef.orderByChild("username").on("child_added", function(snapshot)
{
userlist.push({userKey:snapshot.key,username:snapshot.val().username,password:snapshot.val().password});
});
setTimeout(function()
{
//check if user exist in userlist.
for(var i=0; i<userlist.length;i++)
if (userlist[i].username == usernameArg && userlist[i].password == passwordArg)
correntUser = userlist[i].userKey;
if(correntUser == undefined)
{
//check if undefined
alert("wrong username or password");
document.getElementById("username").value = "";
document.getElementById("password").value = "";
return;
}
mainPage.addHeader();
},2000);
thank you all.
There is no need to manually check all users and see if there is a match with the attempted login credentials when Firebase provides built-in authentication. Password-based accounts require email addresses, although you can combine the username with any domain name to satisfy that requirement as suggested here.
You did not explain what your database structure looks like under the users path, but one way to handle that is to incorporate the user's unique id that gets returned as part of the createUserWithEmailAndPassword password:
function createAccount(email, password) {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(function(userData) {
// account created successfully
usersRef.child(userData.uid).set({
email: email,
creation_date: new Date(),
...
})
}
.catch(function(error) {
...
})
}
Then for login attempts:
function login(email, password) {
firebase.auth().signInWithEmailAndPassword(email, password)
.then(function(userData) {
// login successful
mainPage.addHeader();
})
.catch(function(error) {
alert("wrong username or password");
document.getElementById("username").value = "";
document.getElementById("password").value = "";
})
}
I am looking to fetch Auth User(s) UID from Firebase via NodeJS or Javascript API.
I have attached screenshot for it so that you will have idea what I am looking for.
Hope, you guys help me out with this.
Auth data is asynchronous in Firebase 3. So you need to wait for the event and then you have access to the current logged in user's UID. You won't be able to get the others. It will get called when the app opens too.
You can also render your app only once receiving the event if you prefer, to avoid extra logic in there to determine if the event has fired yet.
You could also trigger route changes from here based on the presence of user, this combined with a check before loading a route is a solid way to ensure only the right people are viewing publicOnly or privateOnly pages.
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User logged in already or has just logged in.
console.log(user.uid);
} else {
// User not logged in or has just logged out.
}
});
Within your app you can either save this user object, or get the current user at any time with firebase.auth().currentUser.
https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onAuthStateChanged
if a user is logged in then the console.log will print out:
if (firebase.auth().currentUser !== null)
console.log("user id: " + firebase.auth().currentUser.uid);
on server side you can use firebase admin sdk to get all user information :
const admin = require('firebase-admin')
var serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://yourprojecturl.firebaseio.com",
});
admin.auth().listUsers().then(data=>{
console.log(data.users)
})
This is an old question but I believe the accepted answer provides a correct answer to a different question; and although the answer from Dipanjan Panja seems to answer the original question, the original poster clarified later in a reply with a different question:
Basically, I need to generate token from UID by Firebase.auth().createCustomToken(UID) to sign in user on firebase with the following function firebase.auth().signInWithCustomToken(token).
Because the original question was clarified that the intent is to use
createCustomToken and signInWithCustomToken, I believe this is a question about using the Firebase Admin SDK or Firebase Functions (both server-side) to provide custom authentication, probably based on a username and password combination, rather than using an email address and password.
I also think there's some confusion over "uid" here, where in the code example below, it does NOT refer to the user's Firebase uid, but rather the uid indicated in the doc for createCustomToken, which shows:
admin
.auth()
.createCustomToken(uid)
.then((customToken) => {
...
In this case, the uid parameter on the createCustomToken call is not the Firebase uid field (which would not yet be known), thus providing a series of frustrating replies to the coder asking this question.
Instead, the uid here refers to any arbitrary basis for logging in for which this custom auth will support. (For example, it could also be an email address, social security number, employee number, anything...)
If you look above that short code block from the documentation page, you'll see that in this case uid was defined as:
const uid = 'some-uid';
Again, this could represent anything that the custom auth wanted it to be, but in this case, let's assume it's username/userid to be paired with a password. So it could have a value of 'admin' or 'appurist' or '123456' or something else.
Answer: So in this case, this particular uid (misnamed) is probably coming from user input, on a login form, which is why it is available at (before) login time. If you know who is trying to log in, some Admin SDK code code then search all users for a matching field (stored on new user registration).
It seems all of this is to get around the fact that Firebase does not support a signInWithUsernameAndPassword (arbitrary userid/username) or even a signInWithUidAndPassword (Firebase UID). So we need Admin SDK workarounds, or Firebase Functions, and the serverless aspect of Firebase is seriously weakened.
For a 6-minute video on the topic of custom auth tokens, I strongly recommend Jen Person's YouTube video for Firebase here:
Minting Custom Tokens with the Admin SDK for Node.js - Firecasts
As of now in Firebase console, there is no direct API to get a list of users, Auth User(s) UID.
But inside your Firebase database, you can maintain the User UID at user level. As below,
"users": {
"user-1": {
"uid": "abcd..",
....
},
"user-2": {
"uid": "abcd..",
....
},
"user-3": {
"uid": "abcd..",
....
}
}
Then you can make a query and retrieve it whenever you need uid's.
Hope this simple solution could help you!
From Firebase docs, use Firebase.getAuth():
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
var authData = ref.getAuth();
if (authData) {
console.log("Authenticated user with uid:", authData.uid);
}
Source:
Firebase.getAuth()