I need your help.
I have an app. I can login with normal (email and password) and using Google Auth.
When i print my informations to console.log, it successfully prints, but I use firebase and i need to firebase.auth().onStateChanged for control the state.
For example, if i login with email and password, then onstateChanged function works with useEffect, and it redirect homepage (because this function know user has signed in), but when i login with google, i can't inform about user signed in or not because of google.
How can i use both google sign in and firebase? How can i tell firebase, i login with google, there are my informations don't worry.
Here google logs (my google name and googleId):
my codes:
google codes:
const GoogleAuth = () => {
const saveFirebase = (email, uid) => {
return firebase.firestore().collection("users").doc(uid).set({
email: email,
});
};
const onSuccess = (response) => {
const name = response.profileObj.name;
const uid = response.profileObj.googleId;
console.log(uid);
console.log(name);
return saveFirebase(name, uid);
};
const handleClick = () => {
return (
<GoogleLogin
clientId="1093050194946-tcn6k22l190klav7cat182leq09luthu.apps.googleusercontent.com"
buttonText="Login"
onSuccess={onSuccess}
onFailure={onSuccess}
cookiePolicy={"single_host_origin"}
theme="dark"
/>
);
};
return <div className="google-button">{handleClick()}</div>;
};
my constant variables:
const [user, setUser] = useState("");
onAuthStateChanged codes with useEffect:
const authListener = () => {
auth.onAuthStateChanged((user) => {
if (user) {
setUser(user);
setUsername(user.displayName);
} else {
}
});
};
useEffect(() => {
authListener();
});
To check if the user loged in with email or Google just use the providerId from user you get from the onAuthStateChanged like here:
const authListener = () => {
auth.onAuthStateChanged((user) => {
if (user) {
setUser(user);
setUsername(user.displayName);
//Here you can se what provider the user used
console.log('provider',user.providerId)
} else {
}
});
};
Related
I'm still new to programming and especially Firebase so there probably will some obvious stuff I missed.
This is supposed to be login/register page. When the user type's in the needed info and click one of the buttons that corresponds to there field. Tt's supposed to load another page. Save that data in a Firebase realtime database and also in authentication.
It's doing the ladder and first but not the second. So I'm stuck with the code I have displayed under this. I read something about needing to give sometime for the data to be send out.
import { firebaseConfig } from "./database.mjs";
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-app.js";
import { getAuth, createUserWithEmailAndPassword,
signInWithEmailAndPassword, onAuthStateChanged,
signOut } from "https://www.gstatic.com/firebasejs/9.15.0/firebase-auth.js";
import {getDatabase, ref, get, set, child, update, remove, push} from "https://www.gstatic.com/firebasejs/9.15.0/firebase-database.js";
const app = initializeApp(firebaseConfig);
const auth = getAuth();
const db = getDatabase();
const UserRegistration = () => {
const Username = document.getElementById('username').value
const Email = document.getElementById("email-signup").value;
const Passwd = document.getElementById("passwd-signup").value;
createUserWithEmailAndPassword(auth, Email, Passwd)
.then((userCredential) => {
const user = userCredential.user;
const loginTime = new Date()
set(ref(db, 'users/' + user.uid),{
user_email: Email,
user_username: Username,
last_login: `${loginTime}`
})
console.log(user, "User Created");
}).then(StatusMonitor())
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log(error.message)
});
}
const UserLogIn = () => {
const Email = document.getElementById("email-signup").value;
const Passwd = document.getElementById("passwd-signup").value;
const auth = getAuth();
signInWithEmailAndPassword(auth, Email, Passwd)
.then((userCredential) => {
const user = userCredential.user;
const loginTime = new Date()
update(ref(db, 'users/' + user.uid), {
last_login: loginTime
});
console.log(user, "Login Successfull");
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
console.log(error.message);
});
StatusMonitor()
}
//Login checker
const StatusMonitor = () => { //This part specifically
onAuthStateChanged(auth, (user) => {
if (user) {
const uid = user.uid;
console.log("User is active");
window.location.replace("./product.html")
}
else {
console.log("User is inactive");
}
})
}
document.getElementById("signup").addEventListener("click", UserRegistration);
document.getElementById('login').addEventListener("click", UserLogIn);
I was able to get it to work with setTimeout but this created it's own problems such as small freezes whenever the thing got triggered and of course the extra time needed for it to load as I can't set to it change based on latency.
Tried to do it with async/await but personally couldn't get it to work.
Any help would be appreciated!
I have an observer who checks whether the user has logged in, if SO, writes it to the AuthUser variable.
But the variable lives only in the observer
export let authUser = "";
const user = auth.currentUser;
function WatchToUser() {
onAuthStateChanged(auth, (user) => {
if (user) {
authUser = user.email;
} else {
}
});
Later I want to check this user on another page, if he is authorized, then show him the database, if not, then send it to the home page. But on another page, the variable is already an empty string.
It turns out that when switching to another html page, the user disappears, what to do?
showUsers.addEventListener("click", () => {
if (authUser != null && authUser != "") {
window.location.replace("users.html");
} else {
modalVisible("Need to login", isError());
}
});
You can create a function that returns a Promise once Auth state is loaded like this:
function getUser() {
return new Promise((resolve, _) => {
const unsub = onAuthStateChanged(auth, (user) => {
unsub();
return resolve(user) // or throw error is user is not logged in
})
})
}
// await getUser()
However, it seems you are calling a function when a button is click. So the auth state could be loaded already so you could just use currentUser (assuming the page is shown to user only if they are authenticated).
showUsers.addEventListener("click", () => {
const user = auth.currentUser;
if (user) {
window.location.replace("users.html");
} else {
modalVisible("Need to login", isError());
}
});
Environment
Firebase JavaScript SDK v8
Question
How can I re-authorize an already-logged-in user with their password? What I want to do is like below:
const password = "some-password"
firebase.reAuthorizeUser(password)
.then(() => console.log("ok"))
.catch(() => console.log("ng"))
Thank you in advance.
You are looking for reauthenticateWithCredential method.
const user = firebase.auth().currentUser;
// TODO(you): prompt the user to re-provide their sign-in credentials
const credential = promptForCredentials();
user.reauthenticateWithCredential(credential).then(() => {
// User re-authenticated.
}).catch((error) => {
// An error ocurred
// ...
});
Checkout reauthenticate a user in the documentation.
You can do a switch case based on providerId, below should help.
user.providerData.forEach((profile) => {
switch (profile.providerId) {
case 'google.com':
user
.reauthenticateWithPopup(new firebase.auth.GoogleAuthProvider())
.then((UserCredential) => {
**//reauthenticated successfully!**
})
})
.catch((error) => {
**//Something is wrong**
})
break
case 'password':
// eslint-disable-next-line no-case-declarations
const credentials = firebase.auth.EmailAuthProvider.credential(
user.email,
userPassword
)
user
.reauthenticateWithCredential(credentials)
.then(() => {
**//reauthenticated successfully!**
},
})
})
.catch(() => {
**//Something is wrong**
})
break
})
SDK v9
import {getAuth, reauthenticateWithCredential, EmailAuthProvider} from "firebase/auth";
const reauthenticate = async () => {
try {
const auth = getAuth();
const user = auth.currentUser;
const credential = await EmailAuthProvider.credential(
email,
password
);
await reauthenticateWithCredential(user, credential);
return true
} catch (e) {
return null
}
}
const credential = promptForCredentials();
this is giving me error
cant find variable: promptForCredentials.
I'm new with Firebase and I'm still learning how it works. I've created a login, signup and logout sections. The users appear registrated and are saved in the authentication section, but I also want to have their data in database when they register for the first time. I thought of using Firestore Database. The problem is that everything seems to work, but nothing appears in my database section. At first I thought that I was not passing any user auth to the function, so i created a condition to test if there's no user auth, then show a warning. However, there's no warning so it means that I passed it properly.
This is how the sign up function works:
export const SignUp = () => {
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const displayName = useRef();
const email = useRef();
const password = useRef();
const passwordConfirmRef = useRef();
const handleSubmit = async e => {
e.preventDefault();
if (password.current.value !== passwordConfirmRef.current.value) {
return setError("Passwords do not match");
}
try {
setError("")
setLoading(true)
const { user } = await auth.createUserWithEmailAndPassword(email.current.value, password.current.value)
const userRef = await handleUserProfile(user, displayName.current.value)
console.log(userRef)
} catch {
setError("Failed to create an account")
}
setLoading(false)
}
I create the user with auth.createUserWithEmailAndPassword and then I pass the user to handleUserProfile
Here's handleUserProfile function:
export const handleUserProfile = async (userAuth, additionalData) => {
if (!userAuth) {
console.warn("No userAuth")
return
}
const { displayName, email } = userAuth;
const timestamp = new Date()
try {
return await firestore.collection("users").add({
displayName,
email,
timestamp,
...additionalData
})
} catch (err) {
console.log(err)
}
return null;
};
Then, nothing appears in my database and nothing gets added. I'm not sure what I'm doing wrong.
The firestore.collections().add function is adding objects (key: value pairs).
It looks like you're not passing an object into handleUserProfile:
const userRef = await handleUserProfile(user, displayName.current.value)
Passing an object into additionalData should solve your issue.
I have the following code which check the user_id if available and then log me in but it logs me in only if I refresh the app. Any idea how to make this happen without this?
This is the order of functions:
First when you click the login button from Login.js:
<TouchableOpacity onPress={handleSubmit(_signIn)} style={{margin: 10, alignItems: 'center'}}>
then _signIn function which is in Login.js
_signIn = (values, dispatch) => {
const email = values.email;
const password = values.password;
dispatch(loginUser(email, password));
}
Now we dispatched email and password to loginUser from authActions.js
export function loginUser(email, password) {
return function (dispatch) {
return axios.post(SIGNIN_URL, { email, password }).then((response) => {
var { user_id, token } = response.data;
onSignIn(user_id); // Here I pass 'user_id' to onSignIn function
}).catch((error) => {
dispatch(addAlert("Could not log in."));
});
};
}
Now we get the user_id from loginUser inside Auth.js
import { AsyncStorage } from "react-native";
const USER_KEY = "auth_key";
export const onSignIn = (user_id) => AsyncStorage.setItem(USER_KEY, user_id);
export const onSignOut = () => AsyncStorage.removeItem(USER_KEY);
export const isSignedIn = () => {
return new Promise((resolve, reject) => {
AsyncStorage.getItem(USER_KEY)
.then(res => {
if (res !== null) {
resolve(true);
} else {
resolve(false);
}
})
.catch(err => reject(err));
});
};
Now in App.js I am calling the function isSignedIn to check if user_id is available and if so will choose which screen to show
constructor(props) {
super(props);
this.state = {
signedIn: false,
checkedSignIn: false
};
}
componentDidMount() {
isSignedIn()
.then(res => this.setState({ signedIn: res, checkedSignIn: true }))
.catch(err => alert("An error occurred"));
}
render() {
const { checkedSignIn, signedIn } = this.state;
// If we haven't checked AsyncStorage yet, don't render anything (better ways to do this)
if (!checkedSignIn) {
return null;
}
const Layout = createRootNavigator(signedIn);
It`s not async function callback issue - I do know how to use it, coz you are already use it in the isSignedIn function.
You did called onSignIn(userId), but you inform nobody about it. Those function, that calls isSignedIn should somehow know about a user logged in.
Based on this issue and previous one, I guess you should choose an architecture of your app (redux or just functional programming or something else) and keep it in mind.
If you wanna use redux, you should dispatch an action about a user logged in and reflect to state change where you need it.