Reputation: 31
I've been trying to create a front-end app with Firebase Authentication (Google sign-in) and Firebase Cloud Function which stores the authenticated user data to Firestore.
saveAuthUserData
) after sign-in.users
).The expected Cloud Function (3) is to send an HTTP POST request to Firestore with the user's profile data.
I wrote this public/index.html
and functions/index.js
(below), but still looking for the way how it should interact with Firebase without any errors, specifically how to send an HTTP POST request from public/index.html
to Cloud Function in functions/index.js
. Both files are deployed on Firebase Hosting.
public/index.html
import { initializeApp } from "firebase/app";
import { getAuth, signInWithPopup,GoogleAuthProvider } from "firebase/auth";
import { getFirestore, collection, doc, setDoc } from "firebase/firestore";
import { getFunctions, httpsCallable } from "firebase/functions";
const config = {
apiKey: "xxxxxx",
authDomain: "yyyyy.web.app",
projectId: "zzzzzz"
};
const app = initializeApp(config);
const db = getFirestore(app);
const provider = new GoogleAuthProvider();
const auth = getAuth();
const functions = getFunctions();
var btn = document.getElementById("#sign-in-with-google");
btn.addEventListener("click", function() {
signInWithPopup(auth, provider).then((result) => {
var credential = GoogleAuthProvider.credentialFromResult(result);
var user = result.user;
if(user !== null) {
var profile = {
email: user.email,
name: user.displayName,
uid: user.uid
};
const setAuthUserData = httpsCallable(functions, "setAuthUserData");
setAuthUserData(profile).then((result) => {
console.log(result.data);
});
}
});
functions/index.js
const admin = require("firebase-admin");
const functions = require("firebase-functions");
admin.initializeApp();
const fireStore = admin.firestore();
const express = require("express");
const axios = require("axios");
const cors = require("cors");
const app = express();
app.use(cors({ origin: true }));
const setAuthUserData = async (profile) => {
var isAuthUserSet = false;
const db = fireStore.collection("users");
const email = profile.email;
if(email) {
const ref = await db.doc(email).set(profile).then(() => {
isUpdated = true;
});
}
}
return isUpdated;
}
app.post("/setAuthUserData/", (req, res) => {
setAuthUserData(req.params.profile).then((response) => res.send(response));
});
const api = functions.https.onRequest(app);
module.exports = { api };
Updated on 9/6/2022
I fixed my code as below by checking this answer, but I couldn't see any changes on Firestore and any success/error messages on both browser's console and GCP's Logs Explorer.
functions/index.js
public/index.html
) to Firestore (users
collection) if its email is valid.const admin = require("firebase-admin");
const functions = require("firebase-functions");
admin.initializeApp();
const fireStore = admin.firestore();
const express = require("express");
const axios = require("axios");
const cors = require("cors");
const app = express();
app.use(cors({ origin: true }));
module.exports.setAuthUserData = functions.https.onCall(async (data, context) => {
var isUpdated = false;
try {
const db = fireStore.collection("users");
const email = data.email;
if(email) {
const ref = await db.doc(email).set(data).then(() => {
isUpdated = true;
});
}
return isUpdated;
} catch (err) {
return err;
}
});
Also, this terminal's screenshot shows how both functions and hosting are deployed.
Just in case, I tried to do the same thing without Cloud Function (as below) and it perfectly works as expected. When a user presses a button, he is asked to sign in with Google and his profile is properly stored in Firestore once authenticated.
public/index.html
import { initializeApp } from "firebase/app";
import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";
import { getFirestore, collection, doc, setDoc } from "firebase/firestore";
import { getFunctions, httpsCallable } from "firebase/functions";
const config = {
apiKey: "xxxxxx",
authDomain: "yyyyy.web.app",
projectId: "zzzzzz"
};
const app = initializeApp(config);
const db = getFirestore(app);
const provider = new GoogleAuthProvider();
const auth = getAuth();
const functions = getFunctions();
var btn = document.getElementById("#sign-in-with-google");
btn.addEventListener("click", function() {
signInWithPopup(auth, provider).then((result) => {
var credential = GoogleAuthProvider.credentialFromResult(result);
var user = result.user;
if(user !== null) {
var profile = {
email: user.email,
name: user.displayName,
uid: user.uid
};
(async() => {
try {
var profile = {
email: user.email,
name: user.displayName,
uid: user.uid
};
const ref = await setDoc(doc(db, "users", user.email), profile);
} catch (err) {
console.error(err);
}
})();
}
});
Updated on 9/7/2022
I fixed my code and finally it's working! The reason why it hadn't been working is a few syntax errors in mine, and there is no problem in what's suggested here.
Upvotes: 1
Views: 985
Reputation: 83163
Since you do
const setAuthUserData = httpsCallable(functions, "setAuthUserData");
setAuthUserData(profile).then((result) => {
console.log(result.data);
});
in your front-end, you need your Cloud Function to be of type Callable;
Something along the following lines:
exports.setAuthUserData = functions.https.onCall(async (data, context) => {
try {
console.log(JSON.stringify(data));
// Do whatever you need with userData, e.g. write to Firestore
const db = fireStore.collection("users");
const email = data.email;
if (email) {
const ref = await db.doc(email).set(data);
};
return { isUpdated: true }
} catch (error) {
console.log(error);
// Don’t do return error but look at the below URL for exact way to send the error to the front end
// See https://firebase.google.com/docs/functions/callable#handle_errors
}
});
Upvotes: 1