i am trying create user with custom claim. I am using Firebase Cloud Functions. The problem is, when i create (Sign Up) an user, the onCreate not trigger. I am following this tutorial of provided by google. https://firebase.google.com/docs/auth/admin/custom-claims
I Deployed my functions and the region is us-central1
Cloud functions version :
firebase-admin": "^8.9.0
firebase-functions": "^3.3.0
I am using Vue JS as Front-end
My functions/Index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.ProccessSignUp = functions.auth.user().onCreate(async (user) =>{
console.log("Email"+user.email);
if (user.email){
const customClaims = {
admin:true
};
return admin.auth().setCustomUserClaims(user.uid,customClaims)
.then(() =>{
const metadataRef = admin.database().ref('metadata/' +user.uid);
return metadataRef.set({refeshTime:new Date().getTime()})
}).catch(err =>{
console.log(err.message)
})
}
});
My SignUpWithEmailAndPassword
userSignUp({dispatch},payload){
firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
.then(user =>{
user.user.sendEmailVerification()
.then(() =>
alert('Your account has been created! Please, verify your account'),
dispatch('userSignOut'),
).catch(err =>{
console.log(err.message)
})
}).catch(err =>{
console.log(err.message)
})
},
oAuthStateChanged
router.beforeEach(async (to, from, next) => {
const user = await new Promise((resolve) => {
firebase.auth().onAuthStateChanged(async user => {
await store.dispatch("autoSignIn", user);
resolve(user)
});
});
const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
if (requiresAuth) {
if (!user){
next(false)
}else {
if (user.emailVerified){
next();
}else {
alert('Please verify your account')
await store.dispatch("userSignOut", user);
}
}
} else {
next()
}
});
As explained in the doc, with Cloud Functions you can "emit a log line from your function, use standard JavaScript logging calls such as console.log and console.error".
Then the Cloud Functions logs are viewable either in the Firebase console, Stackdriver Logging UI, or via the firebase command-line tool.
So you should be able to confirm that your Cloud Function runs correctly (or not) by looking at, for exemple, the Firebase console.
I had the same situation while running cloud funtions locally. My user().onCreate() trigger function was also not triggering.
export const addNewUser = auth
.user()
.onCreate((user) => {
// Do something
})
I tried many things but everything was looking fine. Finally I updated my firebase-tools to latest version by running this command and it started working as a charm.
npm install -g firebase-tools#latest
Hope this helps someone.
Related
I am using react-native-firebase in an ejected expo app and trying to build a presence detection system in my chat app which will detect that if the message recipient is online and if not when was he/she was last online. The data will be stored as follows in firebase realtime database:
{
lastSeen:[{
[userId]:{
state: boolean
time: serverTimeStamp
}
}]
}
The problem is that firebase console never shows the data and only if recipient is online then app shows this data (even though its not visible in console) but if user is offline then nothing is returned and no error generated. I have set read and write to true in realtimeDB rules. Here is the code I am using:
import database from "#react-native-firebase/database";
export const updateUserLastSeen = (userId) => {
const userStatusDatabaseRef = database().ref("/lastSeen/" + userId);
console.log("updatelast", userId);
userStatusDatabaseRef
.set({
state: true,
time: database.ServerValue.TIMESTAMP,
})
.then(() => console.log("online"))
.catch((e) => console.log(e));
// database()
// .ref(".info/connected")
// .on("value", function (snapshot) {
// if (snapshot.val() == false) {
// return;
// }
userStatusDatabaseRef
.onDisconnect()
.set({
state: false,
time: database.ServerValue.TIMESTAMP,
})
.then(function () {
console.log("disconnect configured");
// userStatusDatabaseRef.set({
// state: true,
// time: database.ServerValue.TIMESTAMP,
// });
});
// });
};
export const checkUserLastSeen = (userId, setUserLastSeen) => {
console.log("check last", userId);
database()
.ref("/lastSeen/" + userId)
.on("value", (snapshot) => {
setUserLastSeen(snapshot.val());
console.log("User data: ", snapshot.val());
});
console.log("after check last");
};
I tried both the code from firebase docs and rnfirebase docs. In above code, none of the "then" or "catch" functions get called in updateUserLastSeen but in checkUserLastSeen "on" is invoked only if bearer of userId is online. Also, I am using realtime db only for this purpose and cloud firestore for other data storing and its working fine.
Any help would be appreciated. Thanks.
If neither then nor catch of a write is called, it typically means that the client is not connected to the server.
I recommend checking to make sure your app has a network connection, and that you've configured the (correct) URL for your database.
I have used react-native-firebase version 6.2.0
When I use react-native-firebase/messaging, I found out any sendMessage() function doesn’t work.
(I use android devices and virtual machine.)
I just follow the document here
At first, I registered remoteNotification and got FCM token from it. => init()
Then, I sent upstream remoteMessage => sendMessage()
But, I could not find out where are the messages. => could not receive any messages in device and in firebase cloud messaging console.
When I sent messages from firebase cloud messaging console, I could got the message at devices.
import messaging from '#react-native-firebase/messaging';
import firestore from '#react-native-firebase/firestore';
import store from 'project3/redux/store.js';
export async function init() {
const enabled = await messaging().hasPermission();
if (enabled) {
console.log('user has permissions');
} else {
console.log('user doesnt have permission');
const enabled2 = await messaging().requestPermission();
if (enabled2) {
console.log('requestPermission');
} else {
console.log('not requestPermission');
}
}
console.log('getToken');
await messaging().registerForRemoteNotifications();
const fcmToken = await messaging().getToken();
const uid = store.getState().email;
console.log('fmcToken : ' + fcmToken);
await firestore()
.doc(`users/${uid}`)
.update({
fcmToken: fcmToken,
});
console.log(
'isRegisteredForRemoteNotifications ' +
messaging().isRegisteredForRemoteNotifications,
);
messaging().onMessage(async remoteMessage => {
console.log('FCM Message Data:', remoteMessage.data);
});
messaging().onSendError(event => {
console.log(event.messageId);
console.log(event.error);
});
}
export async function sendMessage() {
console.log('sendMessage');
await messaging()
.sendMessage({
data: {
loggedIn: Date.now().toString(),
uid: store.getState().email,
},
})
.then(msg => {
console.log(msg);
});
}
Please help me.
I found many cases about below version 5.x.x of react-native-firebase.
But, there are very few cases about 6.x.x and guide isn't also sufficient.
You may save my weeks.
So i working with firebase auth and database in order to set new user to data base, if set successful i want to set claims for that user.
So it means i have a promise within a promise:
function setUser(user){
// no need for the database code before this, but userRef is set properly
return userRef.set(user)
.then(succ => {
return firebase.firebase.auth().setCustomUserClaims(user.key, {admin: true})
.then(() => {
console.log("setting claims")
return true;
});
})
.catch(err => {
return err
})
}
calling function:
app.post("/register_user",jsonParser,async (req, res) => {
var user = req.body.user;
let result = await fireBase.setUser(user);
res.send(result);
})
What happens is that i get the set on the database but claims are not set nor i can i see the log. I know its a js question and not firebase one. I tried many different ways (with await) but non worked.
firebase.firebase does not seem correct. You need to be using the admin object which can be initialised using const admin = require('firebase-admin'); This is not part of the firebase db sdk, but the admin one. You can also use the userRef.uid as that gives you the id of the document of the user, if that is what you want, else use your user.key
return admin.auth().setCustomUserClaims(userRef.uid, {
admin: true
}).then(() => {
//on success
});
I have written a firebase Http callable cloud function based on the tutorial here: https://www.youtube.com/watch?v=3hj_r_N0qMs from the firebase team. However, my function is unable to verify the custom claims on a user (me) as 'context.auth' is undefined
I've updated firebase, firebase tools, firebase-functions and admin SDK to the latest versions.
My functions/Index.ts file
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp()
export const addAdmin = functions.https.onCall((data, context) => {
if (context.auth.token.admin !== true) {
return {
error: 'Request not authorized'
};
}
const uid = data.uid
return grantAdminRole(uid).then(() => {
return {
result: `Request fulfilled!`
}
})
})
async function grantAdminRole(uid: string): Promise<void> {
const user = await admin.auth().getUser(uid);
if (user.customClaims && (user.customClaims as any).admin === true) {
console.log('already admin')
return;
}
return admin.auth().setCustomUserClaims(user.uid, {
admin: true,
}).then(() => {
console.log('made admin');
})
}
My app.component.ts code
makeAdmin() {
var addAdmin = firebase.functions().httpsCallable('addAdmin');
addAdmin({ uid: '[MY-USER-ID]' }).then(res => {
console.log(res);
})
.catch(error => {
console.log(error)
})
}
The function executes well if I don't try to access 'context' and I can add a custom claim to this user. However if I try to access context.auth I find the error:
Unhandled error TypeError: Cannot read property 'token' of undefined"
The error message is telling you that context.auth doesn't have a value. As you can see from the API documentation, auth will be null if there is no authenticated user making the request. This suggests to me that your client app does not have a signed-in user at the time of the request to the callable function, so make sure that is the case before invoking the function. If you allow the case where a callable function can be invoked without a signed in user, you will need to check for that case in your function code by checking context.auth before doing work on behalf of that user.
Turns out I wasn't properly integrating AngularFire Functions. I found the solution to my problem here: https://github.com/angular/angularfire2/blob/master/docs/functions/functions.md
I changed my client component code to the following:
import { AngularFireFunctions } from '#angular/fire/functions';
//other component code
makeAdmin() {
const callable = this.fns.httpsCallable('addAdmin');
this.data$ = callable({ uid: '[USERID]' })
.subscribe(resp => {
console.log({ resp });
}, err => {
console.error({ err });
});
}
I'm trying to remove a node from Firebase using cronjob and i have this function but when it gets executed I get an error saying "Error: could not handle the request" and the log says: "database is not defined"
This is my function:
exports.cleanStatsOnRequest = functions.https.onRequest((req, res) => {
const ref1 = firebase.database.ref;
const dbref = ref1.child(`/dailystats`);
console.log('removing dailystats');
return dbref.remove
.then(() => {
res.send('dailystats removed');
})
.catch(error => {
res.send(error);
});
});
What am I doing wrong? What is the right way to define the database?
You need to use the Firebase Admin SDK to access the Realtime Database from an HTTP trigger Cloud Function. This documentation shows you how to read from the database. This example shows writing to the database, which would be similar to deleting.
Try this. database,ref and remove are functions. Read this guide.
Also you should not return dbref.remove() as remove() will return a promise.
exports.cleanStatsOnRequest = functions.https.onRequest((req, res) => {
const ref1 = firebase.database().ref(); // changes here
const dbref = ref1.child('/dailystats');
console.log('removing dailystats');
return dbref.remove() // changes here
.then(() => {
res.send('dailystats removed');
})
.catch(error => {
res.send(error);
});
});