in my app I am getting the uid of the current user by:
also I get the username from :
console.log gives me the right name.
But when I try to write to my db via:
https://movieapp-8a157.firebaseio.com/users/${username}/${authUser}/posts.json?auth=${token}
It doesnt work. If I remove the ${username} it will write in the correct path. Any ideas? I edited my post for more clearness.
export const postJob = data => {
return async (dispatch, getState) => {
const randomColors = ["#f3a683"];
const colorNumber = Math.floor(Math.random() * 20) + 1;
const bgColor = randomColors[colorNumber];
const val = getState();
const userId = val.auth.userId;
const rules = {
description: "required|min:2"
};
const messages = {
required: field => `${field} is required`,
"description.min": "job description is too short"
};
try {
await validateAll(data, rules, messages);
const token = await firebase
.auth()
.currentUser.getIdToken(true)
.then(function(idToken) {
return idToken;
});
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
var displayName = user.displayName;
var email = user.email;
var emailVerified = user.emailVerified;
var photoURL = user.photoURL;
var isAnonymous = user.isAnonymous;
var uid = user.uid;
var providerData = user.providerData;
// ...
} else {
// User is signed out.
// ...
}
});
var user = firebase.auth().currentUser;
const authUser = user.uid;
const username = await firebase
.database()
.ref("users/" + authUser + "/name")
.once("value", function(snapshot) {
console.log("################", snapshot.val());
});
//console.log("#####################", authUser);
const response = await fetch(
`https://movieapp-8a157.firebaseio.com/users/${username}/${authUser}/posts.json?auth=${token}`,
{
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
titel: data.titel,
fname: data.fname,
description: data.description,
cover: data.cover,
friend: data.friend,
ownerId: userId,
bgColor: bgColor
})
}
);
const resData = await response.json();
Your code that's getting the UID isn't working the way you exepct. The auth state listener is asynchronous and is triggering after the line of code that accessesfirebase.auth().currentUser. That line of code is actually giving you the current user before the sign-in completes. That means it's going to be undefined.
You're then using that undefined value to build a reference to a location in the database. This is causing the actual reference to be something other than what you expect. You should add debug logging to see this yourself.
You should be using the callback to determine when exactly the user is signed in, and only read and write that user's location. This means that you should probably move the lines of code that write the database into the callback, when you know that user is correct, and use user.uid to build the database reference for reading and writing.
Related
How can I add a user to the users collection logging in with Gmail?
I tried the addUser but it does not work. I'm quite new to Firebase v9
//firebase
import { signInWithPopup, GoogleAuthProvider } from "firebase/auth";
import { auth, signInWithGoogle, db } from "../../Firebase/utils";
import { doc, setDoc, collection } from "firebase/firestore";
const Login = (props) => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const addUser = async () => {
const userRef = doc(db, "users", auth.currentUser);
setDoc(userRef);
};
useEffect(() => {
addUser();
}, []);
const googleHandler = async () => {
signInWithGoogle.setCustomParameters({ prompt: "select_account" });
signInWithPopup(auth, signInWithGoogle)
.then((result) => {
// This gives you a Google Access Token. You can use it to access the Google API.
const credential = GoogleAuthProvider.credentialFromResult(result);
const token = credential.accessToken;
// The signed-in user info.
const user = result.user;
// redux action? --> dispatch({ type: SET_USER, user });
addUser();
console.log(auth.currentUser, "login page");
})
.catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
// The email of the user's account used.
const email = error.email;
// The AuthCredential type that was used.
const credential = GoogleAuthProvider.credentialFromError(error);
// ...
});
};
return (
<>
<form>
<Button onClick={googleHandler}>Login with Gmail</Button>
</form>
</>
);
};
export default Login;
These are my package.json just to be sure:
This is what the console.log(auth.currentUser) shows:
UPDATE:
const addUser = async (userId) => {
const userRef = doc(db, "users", userId);
return await setDoc(userRef, { ...data });
};
useEffect(() => {
addUser();
}, []);
const googleHandler = async () => {
signInWithGoogle.setCustomParameters({ prompt: "select_account" });
signInWithPopup(auth, signInWithGoogle)
.then(async (result) => {
// This gives you a Google Access Token. You can use it to access the Google API.
const credential = GoogleAuthProvider.credentialFromResult(result);
const token = credential.accessToken;
// The signed-in user info.
const user = result.user;
// redux action? --> dispatch({ type: SET_USER, user });
// addUser();
const { isNewUser } = getAdditionalUserInfo(result);
if (isNewUser) {
await addUser(user.uid);
} else {
console.log("User already exists");
}
})
.catch((error) => {
// Handle Errors here.
const errorCode = error.code;
const errorMessage = error.message;
// The email of the user's account used.
const email = error.email;
// The AuthCredential type that was used.
const credential = GoogleAuthProvider.credentialFromError(error);
// ...
});
};
The doc() function takes Firestore instance as first argument and the rest are path segments (strings) so you cannot pass currentUser object there. Also there might be a chance that auth.currentUser. You can use isNewUser property to check if the user has just signed up or is logging in again and then add the document. Try refactoring the code as shown below:
signInWithPopup(auth, signInWithGoogle)
.then(async (result) => {
const user = result.user;
const { isNewUser } = getAdditionalUserInfo(result)
if (isNewUser) {
await addUser(user.uid);
} else {
console.log("User already exists")
}
})
const addUser = async (userId) => {
const userRef = doc(db, "users", userId);
return await setDoc(userRef, {...data});
};
this is my Register function
createUserWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
const uid = userCredential.user.uid;
const data = {
id: uid,
email,
fullName,
};
async function storeUserUid() {
const newUser = doc(collection(db, "users", user.uid));
await setDoc(newUser, data);
console.log(uid) = aj3x5gAe2jUcngBoTY5cVpOTITu1
console.log(data) = Object {
"email": "lala#email.com",
"fullName": "lala",
"id": "aj3x5gAe2jUcngBoTY5cVpOTITu1",
}
My login function that needs helping. When authenticating it successfully I have console.logged the (uid) which is the first markup in the screenshow below. I am receiving the same uid from the second console.log(userList) under the "id" key. How can I access the object and compare both values so I can let the user then navigate to the "HomeScreen" if there is a match from the signInwithCredentials and the userList id. I need somehow to map through all the docs inside the "users" collection and compare their "id" keys and if there is a match with the signInwithCredentials uid => then, let the user in. MANY THANKS
const onLoginPress = () => {
signInWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
const uid = userCredential.user.uid;
console.log(uid);
async function getUser() {
const q = query(collection(db, "users"));
const userSnap = await getDocs(q);
const userList = userSnap.docs.map((doc) => doc.data());
console.log(userList);
}
getUser();
})
If you don't need to get all user docs, but just the one for the current user, that'd be:
async function getUser() {
const ref = doc(db, "users", FirebaseAuth.instance.currentUser.uid));
const userDoc = await getDoc(ref);
return userDoc.data();
}
getUser();
After importing the AWS module I go ahead and declare the cognitoidentityserviceprovider variable:
let AWS = require("aws-sdk");
let AWS_REGION = "us-east-1";
let USER_POOL_ID = 'us-east-1_4RQvUuPkX';
let AWS_COGNITO_CLIENT_ID = 'l703om838lkem323m04tiparls';
let AWS_COGNITO_IDENTITY_POOL_ID = 'us-east-1:112e122-bdd5-1234-983b-0afff8de2b3f';
AWS.config.update({
region: AWS_REGION,
});
let cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider({
apiVersion: "2016-04-19",
region: AWS_REGION
});
After the initial configuration is set I am ready to define the create_user function that I can use to create a new Cognito user supplying this functions with the user's email and password:
async function create_user(email, password) {
let params = {
UserPoolId: USER_POOL_ID,
Username: email,
DesiredDeliveryMediums: ["EMAIL"],
TemporaryPassword: password,
UserAttributes: [
{
Name: "email",
Value: email
},
{
Name: "email_verified",
Value: "true"
}
]
};
return await cognitoidentityserviceprovider.adminCreateUser(params).promise();
}
Next, I define another function confirm_user which I am going to use to confirm the new user by setting the user's password:
async function confirm_user(sub_id, password) {
let params = {
Password: password,
UserPoolId: USER_POOL_ID,
Username: sub_id,
Permanent: true
};
return await cognitoidentityserviceprovider.adminSetUserPassword(params).promise();
}
With both create_user and confirm_user functions defined I can now create a new Cognito user and confirm it on spot without a need for the user to confirm the sign-up process:
async function main(email, password) {
let user_data = await create_user(email, password);
let sub_id = user_data.User.Attributes[0].Value;
let confirm_data = await confirm_user(sub_id, password);
}
let EMAIL = 'foo#bar.com';
let PASSWORD = 'MY_PASSWORD';
main(EMAIL, PASSWORD)
Since I want to get the user's Identity Pool ID (as identityID variable here) I need to define a third function that I name as authenticate_user(email, password):
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
async function authenticate_user(email, password) {
var authenticationData = {
Username: email,
Password: password,
};
let auth_details = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
let poolData = {
UserPoolId : USER_POOL_ID,
ClientId : AWS_COGNITO_CLIENT_ID
};
let pool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
let userData = {
Username: email,
Pool: pool
};
let cognito_user = new AmazonCognitoIdentity.CognitoUser(userData);
let jwt_token;
await new Promise((resolve) => {
cognito_user.authenticateUser(auth_details, {
onSuccess: (result) => {
jwt_token = result.getIdToken().getJwtToken();
return resolve(jwt_token);
},
onFailure: (err) => {
return resolve(err.message || JSON.stringify(err) );
},
});
});
let logins = {};
logins["cognito-idp." + AWS_REGION + ".amazonaws.com/" + USER_POOL_ID] = jwt_token;
let creds = new AWS.CognitoIdentityCredentials({
IdentityPoolId: AWS_COGNITO_IDENTITY_POOL_ID,
Logins: logins
});
let IdentityId;
await new Promise((resolve) => {
creds.get(function(err) {
IdentityId = creds.data.IdentityId;
resolve(IdentityId);
});
})
return IdentityId;
}
Apparently it is a very long and complex way of getting the user's identityID. Is there a simpler way to get the user federated Identity Pool ID? Aside from the complexity, we need to know the user password to get the user's Identity Pool ID. Is there a way to get it without knowing the user's password?
I am trying to get Firebase to assign users a name based off of what they put into a field. However it appears that the name isnt being updated doesnt do anything.
btnSignUp.addEventListener('click', e => {
//Get Email and Password
const acEmail = email.value;
const acPass = password.value;
const acName = name.value;
const auth = firebase.auth();
//Sign Up
const promise = auth.createUserWithEmailAndPassword(acEmail, acPass);
promise.catch(e => console.log(e.message));
then(function(user) {
user.updateProfile({
displayName: acName
})
}).catch(function(error) {
console.log(error);
});
});
Any help is Appreciated!
The following function works well when tested with shell, and data are created in firestore.
When pushed in prod, it returns Function execution took 60002 ms, finished with status: 'timeout'
Any input?
exports.synchronizeAzavista = functions.auth.user().onCreate(event => {
console.log('New User Created');
const user = event.data;
const email = user.email;
const uid = user.uid;
return admin.database().ref(`/delegates`)
.orderByChild(`email`)
.equalTo(email)
.once("child_added").then(snap => {
const fbUserRef = snap.key;
return admin.firestore().collection(`/users`).doc(`${fbUserRef}`).set({
email: email,
uid: uid
}).then(() => console.log("User Created"));
});
});
Edit
I've update my code with the following, but I still getting Function returned undefined, expected Promise or value but I can't identify where my function return undefined. Why my getUser() function does not return anything?
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.synchronizeAzavista = functions.auth.user().onCreate(event => {
console.log('New User Created');//This log
const user = event.data;
const email = user.email;
const uid = user.uid;
console.log('Const are set');//This log
getUser(email).then(snap => {
console.log("User Key is " + snap.key);//No log
const fbUserRef = snap.key;
return admin.firestore().collection(`/users`).doc(`${fbUserRef}`).set({
email: email,
uid: uid
});
}).then(() => console.log("User Data transferred in Firestore"));
});
function getUser(email) {
console.log("Start GetUser for " + email);//This log
const snapKey = admin.database().ref(`/delegates`).orderByChild(`email`).equalTo(email).once("child_added").then(snap => {
console.log(snap.key);//No Log here
return snap;
});
return snapKey;
}
You're not returning a promise from your write to Firestore.
exports.synchronizeAzavista = functions.auth.user().onCreate(event => {
const user = event.data;
const email = user.email;
const uid = user.uid;
return admin.database().ref(`/delegates`)
.orderByChild(`email`)
.equalTo(email)
.once("child_added").then(snap => {
const fbUserRef = snap.key;
return admin.firestore().collection(`/users`).doc(`${fbUserRef}`).set({
email: email,
uid: uid
});
});
});