Wanting to display error messages when a person has trouble going through the authentication process (wrong password etc). I have a pinia store which has the actions for login etc below.
async loginUser(email, password) {
this.loadingUser = true;
try {
const { user } = await signInWithEmailAndPassword(
auth,
email,
password
);
this.userData = { email: user.email, uid: user.uid };
router.push("/");
} catch (error) {
console.log(error);
this.userData = {};
} finally {
this.loadingUser = false;
}
},
and my login script form component code below.
const email = ref("");
const password = ref("");
const handleSubmit = () => {
if (!email.value || password.value.length < 8) {
alert("Enter");
}
userStore.loginUser(email.value, password.value);
};
how can i display any authentication error on the page to the user? Much appreciated.
Related
I'm trying to make a basic login/signup system with firebase. So far I've been able to fix all the other bugs. The program first creates a user with Firebase Authentication then puts the user data in the Firebase Database. I've managed to get the Authentication working but the database part just makes firebase spit out, "firebase is not defined".
Here's the code:
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.13.0/firebase-app.js";
import { getAuth, createUserWithEmailAndPassword } from "https://www.gstatic.com/firebasejs/9.13.0/firebase-auth.js";
import { getDatabase } from "https://www.gstatic.com/firebasejs/9.13.0/firebase-database.js";
const firebaseConfig = {
apiKey: "AIzaSyCQjuF9A4Km_M7Eo5gnd1B6nmDRRYSle2c",
authDomain: "badge-world.firebaseapp.com",
projectId: "badge-world",
storageBucket: "badge-world.appspot.com",
messagingSenderId: "186421361260",
appId: "1:186421361260:web:852bcaa237f86a76b1f649"
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const database = getDatabase(app);
document.getElementById ("signup-button").addEventListener("click", register);
document.getElementById ("login-button").addEventListener("click", login);
function register() {
let email = document.getElementById('email').value
let password = document.getElementById('password').value
let username = document.getElementById('username').value
if (validate_email(email) == false || validate_password(password) == false) {
alert("Incorrect Fields. Remember password has to have more than 6 characters and there must be a valid email.")
}
if(validate_field(username) == false) {
alert("Username missing")
}
createUserWithEmailAndPassword(auth, email, password)
.then(function (){
var user = auth.currentUser
var rootRef = firebase.database().ref();
var user_data = {
email : email,
password : password,
username: username,
last_login : Date.now
}
rootRef.child('users/' + user.uid).set(user_data)
alert("User Created!")
})
.catch(function(error) {
var error_code = error.code
var error_message = error.message
alert(error_message)
})
}
function login() {
}
// Validate Functions
function validate_email(email) {
let expression = /^[^#]+#\w+(\.\w+)+\w$/
if (expression.test(email) == true) {
// Email is good
return true
} else {
// Email is not good
return false
}
}
function validate_password(password) {
// Firebase only accepts lengths greater than 6
if (password < 6) {
return false
} else {
return true
}
}
function validate_field(field) {
if (field == null) {
return false
}
if (field.length <= 0) {
return false
} else {
return true
}
}
and here's the database part that seems to be causing the issue:
.then(function (){
var user = auth.currentUser
var rootRef = firebase.database().ref();
var user_data = {
email : email,
password : password,
username: username,
last_login : Date.now
}
rootRef.child('users/' + user.uid).set(user_data)
alert("User Created!")
})
.catch(function(error) {
var error_code = error.code
var error_message = error.message
alert(error_message)
})
Any help is appreciated!
You are using Firebase Modular SDK that uses a functional syntax and not the firebase. namespaced one. The problem is this line:
var rootRef = firebase.database().ref();
There is a top level function ref() to get a DatabaseReference now. Try refactoring the code as shown below:
import { getDatabase, ref, set } from "https://www.gstatic.com/firebasejs/9.13.0/firebase-database.js";
// declared while initializing
const database = getDatabase(app)
set(ref(database, 'users/' + user.uid), user_data)
.then(() => {
console.log("data added")
})
.catch((e) => console.log(e))
The documentation has examples of both the syntaxes so make sure you are referring to modular tab.
I am trying to use Firebase Auth in backend, but I can't seem to be able to have the same Auth instance in the front-end as well.
The back-end:
'use strict';
import { firebaseAdmin, auth } from '../firebase.js';
import deleteCollection from '../helpers/deleteCollection.js';
import User from '../models/user.js';
import {
createUserWithEmailAndPassword,
updateProfile,
signInWithEmailAndPassword,
signOut,
setPersistence,
browserLocalPersistence,
} from 'firebase/auth';
const firestore = firebaseAdmin.firestore();
const register = async (req, res, next) => {
try {
// name, email, password
const { name, email, password, avatar } = req.body;
console.log('sent from frontend', { name, email, password });
// Check if email or password were sent
if (!email || !password) {
return res.status(422).json({
email: 'Email is required !',
password: 'Password is required !',
});
}
const usersCollection = firestore.collection('users');
// Reference to a QuerySnapshot whith all users that have the requested name
const userSnapshot = await usersCollection.where('name', '==', name).get();
// Check if user already exists:
if (!userSnapshot.empty) {
throw new Error('Username is taken !');
} else {
await setPersistence(auth, browserLocalPersistence);
// Firebase Auth Create User
await createUserWithEmailAndPassword(auth, email, password);
// User is signed in
const user = auth.currentUser;
if (user) {
await updateProfile(user, {
displayName: name,
});
const setUser = {
id: user.uid,
name: user.displayName,
avatar: avatar,
};
await usersCollection.doc(setUser.id).set(setUser);
res.status(201).send(setUser);
} else {
throw new Error('No user');
}
}
} catch (error) {
const errorCode = error.code;
const errorMessage = error.message;
res.status(400).send(errorMessage);
console.log(errorCode, errorMessage);
}
};
const login = async (req, res, next) => {
try {
const { email, password } = req.body;
await setPersistence(auth, browserLocalPersistence);
const userCred = await signInWithEmailAndPassword(auth, email, password);
const usersCollection = firestore.collection('users');
const userSnapshot = await usersCollection
.where('name', '==', userCred.user.displayName)
.get();
if (userSnapshot.empty) {
throw new Error('User does not exist !');
} else {
let user;
userSnapshot.forEach((doc) => (user = { ...doc.data() }));
res.status(200).send(user);
}
} catch (error) {
res.status(404).send(error.message);
console.log(error);
}
};
const logout = async (req, res, next) => {
try {
// const { name, email, password, avatar } = req.body;
await signOut(auth);
res.sendStatus(200);
} catch (error) {
const errorCode = error.code;
const errorMessage = error.message;
res.status(404).send(errorMessage);
console.log(error);
}
};
I call Register, Login and Logout using Redux thunkAPI:
const register = async (userData) => {
const response = await axios.post(API_REGISTER, userData, {
headers: {
// Overwrite Axios's automatically set Content-Type
'Content-Type': 'application/json',
},
});
if (response.data) {
// localStorage.setItem('user', JSON.stringify(response.data));
}
return response.data;
};
const login = async (userData) => {
const response = await axios.post(API_LOGIN, userData, {
headers: {
// Overwrite Axios's automatically set Content-Type
'Content-Type': 'application/json',
},
});
if (response.data) {
// localStorage.setItem('user', JSON.stringify(response.data));
}
return response.data;
};
const logout = async () => {
const response = await axios.get(`${API_LOGOUT}`);
if (response.data) {
localStorage.removeItem('user');
}
return response.data;
};
export const register = createAsyncThunk(
'user/register',
async (user, thunkAPI) => {
try {
return await userService.register(user);
} catch (error) {
return thunkAPI.rejectWithValue(error.response.data);
}
}
);
export const login = createAsyncThunk('user/login', async (user, thunkAPI) => {
try {
return await userService.login(user);
} catch (error) {
return thunkAPI.rejectWithValue(error.response.data);
}
});
export const logout = createAsyncThunk('user/logout', async (_, thunkAPI) => {
try {
return await userService.logout();
} catch (error) {
return thunkAPI.rejectWithValue(error.response.data);
}
});
I am able to Register a user, to login and to logout, but if I hit refresh I get logged out.
I am not able to persist the Firebase Auth state between front-end and backend.
This is the Private Route component
import { useSelector } from 'react-redux';
import { Navigate, useLocation } from 'react-router-dom';
import { auth } from '../../firebase';
import { useAuthState } from 'react-firebase-hooks/auth';
import { useEffect } from 'react';
import { useState } from 'react';
let isAuth;
export default function PrivateRoute({ children }) {
const location = useLocation();
const [user, setUser] = useState();
// const isAuth = useSelector((state) => state.user.user);
// const [user, loading, error] = useAuthState(auth);
// useEffect(() => {
// if (loading) return;
// if (user) {
// isAuth = true;
// console.log(user);
// }
// }, [user, loading]);
useEffect(() => {
auth.onAuthStateChanged(setUser);
}, []);
return user ? (
children
) : (
<Navigate
replace={true}
to='/login'
state={{ from: `${location.pathname}${location.search}` }}
/>
);
}
As you can see from the commented code, I've tried multiple things before posting here but nothing works.
I don't want to move the Authentication logic from back-end to front-end.
I only want to have access to the same Auth state between back-end to front-end.
The approach you're using is not supported by Firebase. You're supposed to authenticate the user only on the frontend and never on the backend. The frontend SDK will persist a token that identifies the user. You then pass that token to the backend on each call and use it to verify the user so that the backend can decide if the operation they are trying to perform is allowed. This scheme is described in the documentation, and I strongly suggest reviewing that:
If your Firebase client app communicates with a custom backend server, you might need to identify the currently signed-in user on that server. To do so securely, after a successful sign-in, send the user's ID token to your server using HTTPS. Then, on the server, verify the integrity and authenticity of the ID token and retrieve the uid from it. You can use the uid transmitted in this way to securely identify the currently signed-in user on your server.
Again, don't try to sign the user in on your backend using the frontend SDK - that is not supported and it does not scale. Only use the Firebase Admin SDK on the backend to validate the user ID tokens passed from the frontend.
i am encountering a problem concerning firebase authentication
so whenever I submit the form the state will get the signup data but it will not send it to my firebase database
utils.js
export const handleUserProfile = async({ userAuth, additionalData }) => {
if (!userAuth) return;
const { uid } = userAuth;
const userRef = firestore.doc(`users/${uid}`);
const snapshot = await userRef.get();
if (!snapshot.exists) {
const { displayName, email } = userAuth;
const timestamp = new Date();
const userRoles = ['user'];
try {
await userRef.set({
displayName,
email,
createdDate: timestamp,
userRoles,
...additionalData
});
} catch (err) {
console.log(err);
}
}
return userRef;
};
in Signup.js :
handleSubmit = async event => {
event.preventDefault();
const { displayName, email, password, confirmPassword } = this.state;
if (password !== confirmPassword) {
const err = ['Password Don\'t match'];
this.setState({ errors: err })
return
}
try {
const { user } = await auth.createUserWithEmailAndPassword(email, password);
await handleUserProfile(user, { displayName })
this.setState({
...initialState
})
}
catch (err) {
}
}
where i am missing ?
I am using firebase with ReactJS, after creating a user I am sending a confirmation email, after clicking the link, the variable emailVerified remains false no matter what I try.
Here's the code where I create the user and send the email:
const createUserWithEmailAndPasswordHandler = async (event, email, password) => {
event.preventDefault();
try{
const {user} = await auth.createUserWithEmailAndPassword(email, password);
user.sendEmailVerification().then(function() {
user.reload()
}).catch(function(error) {
console.log(error);
});
generateUserDocument(user, {displayName});
}
catch(error){
setError('Error Signing up with email and password');
}
}
And this is the generateDocument code:
export const generateUserDocument = async (user, additionalData) => {
if (!user) return;
const userRef = firestore.doc(`users/${user.uid}`);
const snapshot = await userRef.get();
if (!snapshot.exists) {
const { email,emailVerified, displayName, photoURL } = user;
try {
await userRef.set({
displayName,
email,
emailVerified,
photoURL,
...additionalData
});
} catch (error) {
console.error("Error creating user document", error);
}
}
return getUserDocument(user.uid);
};
Even if I logout and login, refresh the page, it still doesn't change to true.
Thanks for any help!
I am Creating an expo app in which a user can login using Gmail.
I followed this firebase documentation to implement that functionality but whenever I click on login, it doesn't neither save the data in the database nor return any error.
This is my firebase function:
isUserEqual = (googleUser, firebaseUser)=> {
if (firebaseUser) {
var providerData = firebaseUser.providerData;
for (var i = 0; i < providerData.length; i++) {
if (providerData[i].providerId === firebase.auth.GoogleAuthProvider.PROVIDER_ID &&
providerData[i].uid === googleUser.getBasicProfile().getId()) {
// We don't need to reauth the Firebase connection.
return true;
}
}
}
return false;
}
onSignIn = (googleUser)=> {
console.log('Google Auth Response', googleUser);
// We need to register an Observer on Firebase Auth to make sure auth is initialized.
var unsubscribe = firebase
.auth()
.onAuthStateChanged(function(firebaseUser) {
unsubscribe();
// Check if we are already signed-in Firebase with the correct user.
if (!this.isUserEqual(googleUser, firebaseUser)) {
// Build Firebase credential with the Google ID token.
var credential = firebase.auth.GoogleAuthProvider.credential(
googleUser.idToken,
googleUser.accessToken
);
// Sign in with credential from the Google user.
firebase.auth()
.signInAndRetrieveDataWithCredential(credential)
.then(function(result) {
console.log('User signed in');
})
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
// ...
});
} else {
console.log('User already signed-in Firebase.');
}
}.bind(this)
);
};
signInWithGoogleAsync = async() => {
try {
const result = await Expo.Google.logInAsync({
behavior: 'web',
androidClientId: '929952027781-5ao9pp7n5n0sj2n70i5tp7klfro88bgp.apps.googleusercontent.com',
iosClientId: '929952027781-7obs66o3kr59kdhp6ll0c9598ue3u8aa.apps.googleusercontent.com',
scopes: ['profile', 'email'],
});
if (result.type === 'success') {
this.onSignIn(result);
return result.accessToken;
} else {
return {cancelled: true};
}
} catch(e) {
return {error: true};
}
}
And this is my login button:
<TouchableOpacity style={styles.AuthOptionGmail} onPress={() => signInWithGoogleAsync()}>
<Ionicons color='#ffffff' style = {styles.BtnIcon} name="logo-google" size={25}/>
<Text style={{fontSize:16,color:'#ffffff', textAlign:'center'}}>Login with Gmail</Text>
</TouchableOpacity>
Can anyone tell me where I messed up please????
with Expo sdk 32 and above following worked for me , just install "expo-google-app-auth"
import * as Google from "expo-google-app-auth";
signInWithGoogleAsync = async () => {
console.log("signInWithGoogleAsync");
try {
//clientId
const { type, accessToken, user, idToken } = await Google.logInAsync({
behavior: "web",
androidClientId:
"your id",
iosClientId:
"your id",
scopes: ["profile", "email"]
});
if (type === "success") {
console.log("accessToken" + accessToken);
console.log("idToken" + idToken);
console.log(user);
return accessToken;
} else {
return { cancelled: true };
}
} catch (e) {
console.log(e);
return { error: true };
}
};