I am attempting to implement a function in my Vue.js Firebase app that deletes/removes users by UID. The app is set up to enable registration of users in Firebase authentication via email and password. Once logged in, the user should be able to click delete in order to remove his/her email and password from Firebase authentication, as well as user data. So far I have the following for the delete function:
async deleteProfile () {
let ref = db.collection('users')
let user = await ref.where('user_id', '==',firebase.auth().currentUser.uid).get()
user.delete()
}
...but I am getting user.delete() is not a function. How can I set up this function to delete the user in authentication and database? Thanks!
UPDATED FUNCTION
async deleteProfile () {
let ref = db.collection('users')
let user = await ref.where('user_id', '==', firebase.auth().currentUser.uid).get()
await user.ref.delete()
await firebase.auth().currentUser.delete()
}
In your code, user is a DocumentSnapshot type object. If you want to delete the document, you can use user.ref.delete(). It returns a promise, so you will need to await it.
Deleting a document will not also delete a user account in Firebase Authentication. If you want to delete the user account, you will have to use the Firebase Authentication API for that. firebase.auth().currentUser.delete().
try this
<button class="..." #click="deleteProfile(currentUser.uid)">Delete</button>
and
methods: {
async deleteProfile(dataId) {
fireDb.collection("yourCollection").doc(dataId).delete()
.then(() => {
alert('Deleted')
})
}
}
Building off Doug Stevenson's answer, this is the function that ultimately worked.
async deleteProfile (user) {
await db.collection("users").doc(user).delete()
await firebase.auth().currentUser.delete()
}
await db.collection("users").doc(user).delete() accepts "user" as an argument from the click event in the DOM, in order to target the doc of the specified user in the database (I don't know why I didn't think of that sooner!) await firebase.auth().currentUser.delete() removes currentUser from firebase authorization.
Related
I am building a chat app and I am trying to figure out the banning system. The idea if the user is in the banned collection becaused he used banned words, block authentication from his account. The problem is that for some reason it does execute the code but rather only does the signInWithRedirect() function. Take a look at my code:
const googleProvider = new GoogleAuthProvider();
const signInWithGoogle = async () => {
try {
const res = await signInWithRedirect(auth, googleProvider);
const user = res.user;
const q = query(collection(db, "banned"), where("uid", "==", user.uid));
const docs = await getDocs(q);
if (docs.exists()) {
//if exists ban the user
console.log('you cannot use this chat app , you are banned!)
Here is also the LoginPage.jsx
function LoginPage() {
const [user] = useAuthState(auth)
const navigate = useNavigate()
console.log(user)
return (
<div>
<div style={{'display': 'none'}}>
<Navbar />
</div>
<Welcome />
</div>
)
}
Here is also signOut
const navigate = useNavigate()
const signOutWithGoogle = () => {
signOut(auth)
navigate('/')
}
Here is firebase firestore
I tried this with promises but nothing happened , I used async , nothing happened
I would not implement such a "banning" system only based on front-end code. It would actually be quite easy for a malicious end-user to bypass your check based on a standard query to a collection.
I would use a Firebase Security Rule to enforce the banishment: Security Rules stand between your data and malicious users and are executed/checked in the back-end. To be complete, with this approach the user will still be authenticated and signed-in but will not be able to interact with the Firebase back-end services like Firestore or Cloud Storage.
Concretely you could as follows:
Write a security rule based on a specific collection in which you create a document per banned user with the user ID as document ID. Then you can use the exists() method to check if the user is banned or not.
Use a Cloud Function to ban (and maybe "un-ban") a user. Again, with Cloud Function the code is executed in the back-end and you therefore avoid the possibility that a malicious user writes a code that could "un-ban" him.
I am using react. I want to delete old subscription when user changes his subscription plan.
this is my code.
import {loadStripe, useStripe} from '#stripe/stripe-js'
const loadCheckout = async (priceId) =>{
const docRef = await db
.collection('customers')
.doc(user.uid)
.collection('checkout_sessions')
.add({
price:priceId,
success_url:window.location.origin,
cancel_url: window.location.origin,
})
docRef.onSnapshot(async (snap) =>{
const {error, sessionId} = snap.data();
if(error){
alert(`an error occured ${error.message}`)
}
if(sessionId){
const stripe = await loadStripe("pk_test_51JG0BKLXYmn2IpSgISeCDbsCNllISGA3PvEbSzBz5bpo8WTvmqI6UKCbzpxX92LKiN0hftRrobm1J6wJZPCOWSTs0081pmQFJE")
const deleted = await stripe.subscriptions.del(
subscription.id
);
console.log(deleted)
stripe.redirectToCheckout({sessionId});
}
})
}
my code give an error saying stripe.subscriptions.del is not a function.
the code work if I remove this line the payment is successful and all.
In stripe API Docs its says to use .del() but it isnt working here.
Your React code uses Stripe.js which is a client-side library. It cannot modify Subscriptions, only secret key API calls can do that which Stripe.js does not use.
You need to make the request to update/delete the Subscription, you need to make the request server-side (in your Firebase app) using the stripe-node library and your secret API key: https://stripe.com/docs/api/subscriptions/cancel?lang=node.
You can use "customer portal" option inside Stripe to avoid backend coding.
It will generate a link to a page where your customer will be able to cancel the subscription.
Inside Stripe: Billing -> subscriptions -> Setup Customer portal
I have a little twisted problem with my React app. I'm using Firebase for authentication. What I need to do is to register a user and set their displayName immediately. Entire problem could be avoided if Firebase allowed to call createUserWithEmailAndPassword() without signing user in, but it doesn't.
I do this:
const submitHandler = async event => {
event.preventDefault();
const auth = await firebase.auth();
const { user } = await auth.createUserWithEmailAndPassword(email, password);
await user.updateProfile({
displayName: userName
});
};
The problem is that I'm using firebase.auth().onAuthStateChanged() in my root component to handle current user state, so it's called as soon as createUserWithEmailAndPassword() is done, before the profile is updated. I'm not sure how to tell onAuthStateChanged() about the updated displayName.
I managed to create a working solution, but I'm not happy with it. I tricked onAuthStateChanged() to ignore users without displayName like so:
useEffect(() => {
const unsubscribeAuth = firebase.auth().onAuthStateChanged((user) => {
if (user === null || user.displayName !== null) {
setLoggedInUser(user);
}
});
return () => unsubscribeAuth();
}, []);
And in my sign up component, I do this:
const submitHandler = async event => {
event.preventDefault();
const auth = await firebase.auth();
const { user } = await auth.createUserWithEmailAndPassword(email, password);
await user.updateProfile({
displayName: userName
});
await auth.signOut();
await auth.updateCurrentUser(user);
};
That's obviously hackish and slower than necessary, because I'm signing in twice. It works as intended though, ignoring the auto-login, then signing out (doing nothing, as the user state hasn't been updated before) and then signing in, triggering onAuthStateChanged() with the updated user.
How can I improve my app to sign up users without this double madness?
Updating the user profile not normally execute the onAuthStateChange listener, as (usually) the authentication state won't change because of this API call.
You can force a reload of the user's ID token to get their latest profile information.
I want to add Google, Facebook and custom login to my Angular7 web app.
Is the UID identifier given by each provider unique ? I mean, can I use it as a user ID in my users Firestore collection ?
And if that's the case, can I still use the createId() method to generate this ID myself in my custom login ? Or might it be the same as one of the providers UIDs ?
Yes you can use it as an UID in your users collection.
Here is my authentification flow:
1/ User creates a new account with email/password
async signUpWithPassword(email, password) {
await firebase.auth().createUserWithEmailAndPassword(email, password)
// user created!
}
2/ I run a cloud function with the auth's onCreate triggers to save the user to my collection:
export const createUserProfile = functions.auth
.user()
.onCreate((user: admin.auth.UserRecord) => {
const { uid } = user
const userRef = db.doc(`users/${uid}`)
// Save it to firestore
return userRef.set({ points: 200 })
})
3/ If this user tries to register with another provider (Google/Facebook etc.), I detect if he's using the same email address, if so I link the new provider to the current one via account linking:
https://firebase.google.com/docs/auth/web/account-linking
That way, the user is going to have multiple auth providers attached to one unique UID/profile.
I'm using firebase web authentication to log users into my website which works perfectly fine - but I want to be able to show the name of the user logged in. How do I do that?
When a user signs up, it will be written with some basic fields (email, uniqueID, etc) to the Firebase Authentication DB (which you have access to, but you don't have full control of, since it's controlled by the Firebase Auth system).
Once your brand new user is created, you'll get a UserCredential object with basic information of your user. Use the uniqueID field (UserCredential.user.uid) to write your user details with as many fields as you want (username, email, fullName, address, preferences, etc) to your Firebase database (realtime DB or cloud Firestore). I think it's a good practice to store under a document with the uniqueID created by the Auth system.
Once you've done that, and that users logins in at a later time, you'll get another userCredential object that contains the uniqueID for that user.
You'll use that uniqueID to access your database where you stored your users details and you will be able to retrieve all the data that you want.
See the code below (I'm using React): uppon a successful signUp, we get a UserCredential object, which we can use to read the uniqueId uid that it was just created, and use that to create a document in our database with that same id. We can add as many fields as we want. In this case, I added username (which I'm getting from my signup form) and email (which I'm getting directly from the UserCredential object).
UserCredential docs
Create User with Password and Email docs
handleSubmit(event){
event.preventDefault();
const { email, passwordOne} = this.state;
// SIGN UP FUNCTION
this.props.firebase.auth.createUserWithEmailAndPassword(email, passwordOne)
// SAVING USER DETAILS TO MY DATABASE
.then((UserCredential) => {
const username = this.state.username;
this.props.firebase.db.collection('users').doc(UserCredential.user.uid)
.set({
username: username,
email: UserCredential.user.email
})
.then( () => {
this.setState({ ...INITIAL_STATE });
this.props.history.push('/');
}
)
.catch(error => {
this.setState({ error });
}
);
}
)
.catch(error => {
this.setState({ error });
}
);
}