I'm trying to make a Username and Password Authentication in a web app that is made with react and firebase.
But I'm really new to firebase and I couldn't find any good documentation about the process, I have read about Firestore but I don't know how to connect it to the authentication method. Any help or hint is appreciated!
Here is the signup function of my /register route.
async function handleSubmit(e) {
e.preventDefault()
if (passwordRef.current.value !== passwordConfirmationRef.current.value){
return setError('Passwords do not match');
}
try {
setError('')
setLoading(true)
await signup(emailRef.current.value, passwordRef.current.value, usernameRef.current.value)
Home()
} catch {
setError('Failed to create an account')
}
setLoading(false)
}
And this is my 'AuthContext.JSX' code:
import React, { useContext , useEffect, useState } from 'react'
const AuthContext = React.createContext()
import {auth} from '../firebase'
export function useAuth() {
return useContext(AuthContext)
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState()
const [loading, setLoading] = useState(true)
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password)
}
function login(email, password) {
return auth.signInWithEmailAndPassword(email, password)
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
setCurrentUser(user)
setLoading(false)
})
return unsubscribe
}, [])
auth.onAuthStateChanged(user => {
setCurrentUser(user)
})
const value = {
currentUser,
signup,
login
}
return (
<AuthContext.Provider value={value}>
{!loading && children }
</AuthContext.Provider>
)
}
Just to let you know the authentication is working well the only problem is getting the Display Name and exporting it to the home page for display.
I want to display the username on this page
Thanks to Dhamaraj I used the updateProfile() function inside my Register route, and it worked properly for adding a display name to the user which I used on the home page for the profile display.
That is the new function, may it helps somebody with the same issue:
async function handleSubmit(e) {
e.preventDefault()
if (passwordRef.current.value !== passwordConfirmationRef.current.value){
return setError('Passwords do not match');
}
try {
setError('')
setLoading(true)
await signup(emailRef.current.value, passwordRef.current.value)
auth.currentUser.updateProfile({
displayName: usernameRef.current.value
}).then(() => {
console.log('Username is: ' + auth.currentUser.displayName)
}).catch((error) => {
console.log('An error was occured while updating the profile.')
});
Home()
} catch {
setError('Failed to create an account')
}
setLoading(false)
}
Related
This question already has an answer here:
How to use firebase authentication with Redux Toolkit using onAuthStateChanged?
(1 answer)
Closed 7 months ago.
I am trying to set the auth status for the currently logged-in user using redux-toolkit's createAsyncThunk and firebase's onAuthStatechanged, but I cannot do so. I am trying to implement a private route that can only be accessed if a user is logged in.
*What I have tried
I create an authService.js file where I created a function checkAuthStatus which calls onAuthStateChanged and returns a user if a user is there else null and then from authSlice, I have exported another function checkUserStatus which returns a promise, and when it gets fulfilled the user will be set to the user returned but the returned value is always null even if the user is logged in.
const checkAuthStatus = () => {
onAuthStateChanged(auth, (user) => {
console.log(user);
return user ? user : null;
});
};
const authService = {
registerUser,
loginUser,
checkAuthStatus,
};
export default authService;
export const checkUserStatus = createAsyncThunk('auth/checkAuth', () => {
return authService.checkAuthStatus();
});
.addCase(checkUserStatus.pending, (state, action) => {
state.isLoading = true;
})
.addCase(checkUserStatus.fulfilled, (state, action) => {
state.user = action.payload;
state.isLoading = false;
});
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Outlet, Navigate } from 'react-router-dom';
import { checkUserStatus } from './../features/auth/authSlice';
import Loader from './Loader';
const PrivateComponent = () => {
const { user, isLoading } = useSelector((state) => state.auth);
const dispatch = useDispatch();
useEffect(() => {
dispatch(checkUserStatus());
}, [dispatch]);
if (isLoading) {
return <Loader />;
}
return user ? <Outlet /> : <Navigate to="/login" />;
};
export default PrivateComponent;
Problem
I am not sure why but the function in the authSerice file checkAuthStatus is returning null even if the current user is not null. One more thing is that the user field from the state is not even there in the redux dev tools, check images for more.
Here is my code:-
authService.js authService Page Image
authSlice.js authSlice function || authSlice extrareducer
PrivateComponent.js Private Route component
App.js Routes for app
one more thing I have notice is the user state is not even there as redux dev tools are showing
this is pending
before
this is fulfilled
after
I have changed the code and now the auth is working but on refreshing the page the user status is user get redirected to login page why?
How to set authentication status with firebase using onAuthStateChanged ?
There are many way to achieve this:
Using global store
const userSlice = createSlice({
name: "users",
initialState,
reducers: {
setLoginStatus: (state, action) {
state.loginStatus = action.payload;
}
},
extraReducers: {
[createUser.fulfilled]: (state, action) => {
state.loginStatus = true;
},
[createUser.rejected]: (state, action) => {
state.loginStatus = false;
},
},
});
// trackUserAuth.ts
onAuthStateChanged(auth, (user) => {
if (user) {
store.dispatch(setLoginStatus(true))
} else {
store.dispatch(setLoginStatus(true))
}
});
Using hooks
export const useAuth = () => {
const dispatch = useDispatch();
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
dispatch(setLoginStatus(true))
} else {
dispatch(setLoginStatus(true))
}
});
return unsubscribe;
}, []);
}
Using thunks
export const checkAuthStatus = () => (dispatch) {
const unsubscribe = Firebase.auth().onAuthStateChanged(user => {
if (user) {
dispatch(setLoginStatus(true))
} else {
dispatch(setLoginStatus(true))
}
});
return unsubscribe;
}
So I'm working on a react native authentication screen. I'm storing the token in AsyncStorage (yea I know it's not the best solution).
So what's happening is when I log in, the token is stored, but the getItem on my Authentication.js screen is not being triggered, and the profile screen is not being called.
If I log in and then manually refresh the app, I am redirected to the profile screen.
Login.js
function Login({navigation}) {
const [signIn, {data}] = useMutation(USER_SIGNIN_MUTATION);
const [userName, setUserName] = useState('');
const [password, setPassword] = useState('');
function handleLogIn() {
signIn({
variables: {
email: userName,
password: password,
},
});
}
useEffect(() => {
if (data != null) {
setToken();
}
});
const setToken = async () => {
try {
console.log('before');
await AsyncStorage.setItem('token', data.signIn.token);
console.log('after');
} catch (error) {
console.log(error);
}
};
return(
...
)
}
Authentication.js
function Authentication() {
const [localToken, setLocalToken] = useState(false);
useEffect(() => {
const fetchUser = async () => {
try {
console.log('before get');
const userData = await AsyncStorage.getItem('token');
if (userData !== null) {
setLocalToken(true);
}
} catch (error) {
console.log(error);
}
};
fetchUser();
}, [localToken]);
console.log(`auth screen - ${localToken}`);
return (
<NavigationContainer>
{localToken === true ? <ProfileStack /> : <AuthStack />}
</NavigationContainer>
);
}
export default Authentication;
also same happens with the logout function when fired. (the function runs, but I need to refresh the app to get back to the login screen)
Profile.js
function Profile({navigation}) {
function signOut() {
logOut();
}
const logOut = async () => {
try {
console.log('before clear');
await AsyncStorage.removeItem('token');
console.log('after clear');
} catch (error) {
console.log(error);
}
};
return (
...
)
}
I'm grateful for any insight on this.
useEffect(() => {
const fetchUser = async () => {
try {
console.log('before get');
const userData = await AsyncStorage.getItem('token');
if (userData !== null) {
setLocalToken(true);
}
} catch (error) {
console.log(error);
}
};
fetchUser();
}, [localToken]);
Here you added the localToken variable in the dependency array of the useEffect. So you are basically saying: run this effect only if the localToken variable changes. But you change that from within the effect only. So try to remove it and keep the dependency as []. This way the effect will run when the component is rendered.
About the fact that you have to refresh the page, it is important to understand why this happens.
<NavigationContainer>
{localToken === true ? <ProfileStack /> : <AuthStack />}
</NavigationContainer>
Here you are rendering ProfileStack or AuthStack based on the localToken value. When you logout, you remove the token from the AsyncStorage but this is not enough. You actually need to trigger a rerender in the Authentication component so the localToken is reevaluated. Basically, when you logout you also need to set setLocalToken(false). So you need to access setLocalToken function from the Profile component. You can pass this function as a prop or better you can use Context API
I am trying to create a project in that login functionality is good and working properly but when I logged in and refreshed the screen the logout button disappears and the login link will come and then again logout button will come.to understand perfectly watch the video https://drive.google.com/file/d/1UvTPXPvHf4EhcrifxDEfPuPN0ojUV_mN/view?usp=sharing, this is because of
const AuthContext = React.createContext()
//useauth will return the AuthContext
export const useAuth = () => {
return useContext(AuthContext)
}
export const Authprovider = ({ children }) => {
var name
auth.onAuthStateChanged((user) => {
name = user
})
const [currentuser, setcurrentuser] = useState(name)
const [load, setload] = useState(true)
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password)
}
function login(email, password) {
return auth.signInWithEmailAndPassword(email, password)
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
setcurrentuser(user)
setload(false)
})
return unsubscribe
}, [])
const value = {
currentuser,
signup,
login,
load,
}
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
}
I wrapped the AuthProvider component around the app component so that I can use the values like current user .
in Header component where login link, logout button is there
const { currentuser, load } = useAuth()
const logout = () => {
try {
auth.signOut().then(() => {
console.log('logged out')
})
} catch {
alert('logout is not possible')
}
}
//some code
{currentuser ? (
<button onClick={logout}>Logout</button>
) : (
<Link to='/login'>Login</Link>
)}
if there is a current user then the logout button will appear otherwise login link will appear but when refreshing there is some problem I tried many ways now I am out of ideas. "Even I refresh the page when logged in the logout button should not disappear" can you tell me how to do this?
to understan watch the video in the link
That's because you're not using load state try this:
//some code
{ load ? <div>loading</div>
: currentuser ? (
<button onClick={logout}>Logout</button>
) : (
<Link to='/login'>Login</Link>
)}
Okay, there's this simple REACTJS app, where firebase is used.
There once you login everything works fine except when you hit the refresh icon. The moment you do it, it redirects you to the previous place where you were asked to login. That's the problem that this newly-born coder is trying to solve!
I can give you following snippets of code:
This is of the landing page
function Landing() {
const [{ }, dispatch] = useStateValue();
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE)
// .then(function () {
// console.log("successfully set the persistence");
// return firebase.auth().signInWithPopup(provider);
// })
.catch(function (error) {
console.log("failed to ser persistence: " + error.message)
});
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('user is logged in');
} else {
console.log('user is logged out now')
}
});
const signIn = () => {
auth
.signInWithPopup(provider)
.then((result) => {
dispatch({
type: actionTypes.SET_USER,
user: result.user
})
}).catch((error) => alert(error.message))
}
reducer.js snippet
export const initialState = {
user: null,
}
export const actionTypes = {
SET_USER: 'SET_USER',
LOGOUT_USER: 'LOGOUT_USER'
}
const reducer = (state, action) => {
console.log(action)
switch (action.type) {
case actionTypes.SET_USER:
return {
...state,
user: action.user,
}
case actionTypes.LOGOUT_USER:
return {
...state,
user: null,
}
default:
return state;
This is of firebase.js
Yes, Google Authentication is what's being used here
import firebase from 'firebase';
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
//config
};
// const user = firebase.auth().currentUser;
// console.log(user);
const firebaseApp = firebase.initializeApp(firebaseConfig)
const db = firebaseApp.firestore();
const storage = firebase.storage();
const auth = firebaseApp.auth();
const provider = new firebase.auth.GoogleAuthProvider();
export default db;
export { auth, provider, storage }
Finally here is of the app.js
function App() {
const [{ user }, dispatch] = useStateValue();
console.log(user);
return (
<div className="app">
{!user ? (
<Landing />
) : (
<App />
)
</div>
Your attention to this matter is greatly appreciated!
Oh by the way this following question is also related to this. It might help you to get a better idea of this issue. So make sure to take a look at that as well!
How can you persist a logged-in user with firebase?
Thanks again!
sample code. work
import firebase from 'firebase/app';
import 'firebase/auth';
import { useEffect, useState } from 'react';
import firebaseConfig from './firebase-config';
const firebaseApp = firebase.initializeApp(firebaseConfig);
const googleProvider = new firebase.auth.GoogleAuthProvider();
firebaseApp.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION)
.then(function () {
// return firebaseApp.auth().signInWithPopup(googleProvider)
})
.catch(function (error) {
console.log(error)
});
function App() {
const [user, setUser] = useState(null)
useEffect(() => {
firebaseApp.auth().onAuthStateChanged((res) => {
console.log("onAuthStateChanged", res)
if (res) {
setUser(res)
// console.log('user is logged in', user);
} else {
setUser(null)
// console.log('user is logged out now')
}
});
}, [])
const signInWithGoogle = (e) => {
firebaseApp.auth()
.signInWithPopup(googleProvider)
.then((result) => {
// console.log(result)
// setUser(result.additionalUserInfo)
}).catch(err => {
// console.log(err)
})
}
const signOut = (e) => {
firebaseApp.auth().signOut()
}
return (
<div>
<h1>Firebase Authentication</h1>
{
user
? (
<div>
<p>Hello, {user.displayName}</p>
<button onClick={signOut}>Sign out</button>
</div>
)
: (
<div>
<p>Please sign in.</p>
<button onClick={signInWithGoogle}>Sign in with Google</button>
</div>
)
}
</div>
);
}
export default App;
Good day Developers. Please i am new to react native and i want to use firebase auth for a project. But i don't know how to accept user name and country with the normal auth().createUserWithEmailAndPassword method. Below is my code so far.. But it does work fine.
import React, {createContext, useState} from 'react';
import { StyleSheet, ActivityIndicator, View, Text, Alert } from 'react-native'
import auth from '#react-native-firebase/auth';
import firebase from '#react-native-firebase/app';
export const AuthContext = createContext();
export const AuthProvider = ({children}) => {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider
value={{
user,
setUser,
login: async (email, password) => {
try {
await auth().signInWithEmailAndPassword(email, password);
} catch (e) {
console.log(e);
Alert.alert(
e.message);
}
},
register: async (name, email, password) => {
try {
await auth().createUserWithEmailAndPassword(email, password);
firebase.auth().currentUser.updateProfile({
displayName: name
});
Alert.alert("Success ✅", "Account created successfully")
return {};
}
catch (e) {
Alert.alert(
e.message );
}
},
forgot: async (email) => {
try {
await firebase.auth().sendPasswordResetEmail(email);
Alert.alert("Success ✅", "A Password Recorvery Link has been sent to your mail.")
}
catch (e) {
Alert.alert(
e.message );
}
},
logout: async () => {
try {
await auth().signOut();
} catch (e) {
Alert.alert(
e.message );
}
},
sendver: async () => {
try {
await firebase.auth().currentUser.sendEmailVerification();
} catch (e) {
Alert.alert(
e.message );
}
},
}}>
{children}
</AuthContext.Provider>
);
};
I will really appreaciate if anyone can help. thanks so much.
Try this way
firebase.auth().signInWithEmailAndPassword("abc#gmail.com", "******")
.then(function(user) {
// Success
})
.catch(function(error) {
// Error Handling
});
Note: Save user info on success in your database