I can successfully login with the below code, however I don’t believe react is receiving any auth data back form google to update the current user in react.
I know I am missing something here but I don’t know what. Any help would be appreciated!
import {useState} from 'react'
import * as Yup from 'yup'
import clsx from 'clsx'
import {Link} from 'react-router-dom'
import {useFormik} from 'formik'
import {getUserByToken, login} from '../core/_requests'
import {toAbsoluteUrl} from '../../../../_metronic/helpers'
import {useAuth} from '../core/Auth'
import {
auth,
db,
signInWithGoogle,
logInWithEmailAndPassword,
registerWithEmailAndPassword,
sendPasswordReset,
logout,
} from "../../../../firebase.js";
import { Firestore } from 'firebase/firestore'
import { useNavigate } from 'react-router-dom';
const loginSchema = Yup.object().shape({
email: Yup.string()
.email('Wrong email format')
.min(3, 'Minimum 3 symbols')
.max(50, 'Maximum 50 symbols')
.required('Email is required'),
password: Yup.string()
.min(3, 'Minimum 3 symbols')
.max(50, 'Maximum 50 symbols')
.required('Password is required'),
})
const initialValues = {
email: '[email protected]',
password: 'demo',
}
/*
Formik+YUP+Typescript:
https://jaredpalmer.com/formik/docs/tutorial#getfieldprops
https://medium.com/@maurice.de.beijer/yup-validation-and-typescript-and-formik-6c342578a20e
*/
export function Login() {
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
const formik = useFormik({
initialValues,
validationSchema: loginSchema,
onSubmit: async (values, { setStatus, setSubmitting }) => {
setLoading(true);
try {
await logInWithEmailAndPassword(values.email, values.password);
setLoading(false);
navigate('/dashboard');
} catch (error) {
console.error(error);
setSubmitting(false);
setLoading(false);
//setStatus(error.message);
}
},
});
return (
<form
className='form w-100'
onSubmit={formik.handleSubmit}
noValidate
id='kt_login_signin_form'
>
{/* begin::Heading */}
<div className='text-center mb-10'>
<h1 className='text-dark mb-3'>Sign In to Web Construct</h1>
<div className='text-gray-400 fw-bold fs-4'>
New Here?{' '}
<Link to='/auth/registration' className='link-primary fw-bolder'>
Create an Account
</Link>
</div>
</div>
{/* begin::Heading */}
{formik.status ? (
<div className='mb-lg-15 alert alert-danger'>
<div className='alert-text font-weight-bold'>{formik.status}</div>
</div>
) : (
<div className='mb-10 bg-light-info p-8 rounded'>
<div className='text-info'>
Use account <strong>[email protected]</strong> and password <strong>demo</strong> to
continue.
</div>
</div>
)}
{/* begin::Form group */}
<div className='fv-row mb-10'>
<label className='form-label fs-6 fw-bolder text-dark'>Email</label>
<input
placeholder='Email'
{...formik.getFieldProps('email')}
className={clsx(
'form-control form-control-lg form-control-solid',
{'is-invalid': formik.touched.email && formik.errors.email},
{
'is-valid': formik.touched.email && !formik.errors.email,
}
)}
type='email'
name='email'
autoComplete='off'
/>
{formik.touched.email && formik.errors.email && (
<div className='fv-plugins-message-container'>
<span role='alert'>{formik.errors.email}</span>
</div>
)}
</div>
{/* end::Form group */}
{/* begin::Form group */}
<div className='fv-row mb-10'>
<div className='d-flex justify-content-between mt-n5'>
<div className='d-flex flex-stack mb-2'>
{/* begin::Label */}
<label className='form-label fw-bolder text-dark fs-6 mb-0'>Password</label>
{/* end::Label */}
{/* begin::Link */}
<Link
to='/auth/forgot-password'
className='link-primary fs-6 fw-bolder'
style={{marginLeft: '5px'}}
>
Forgot Password ?
</Link>
{/* end::Link */}
</div>
</div>
<input
type='password'
autoComplete='off'
{...formik.getFieldProps('password')}
className={clsx(
'form-control form-control-lg form-control-solid',
{
'is-invalid': formik.touched.password && formik.errors.password,
},
{
'is-valid': formik.touched.password && !formik.errors.password,
}
)}
/>
{formik.touched.password && formik.errors.password && (
<div className='fv-plugins-message-container'>
<div className='fv-help-block'>
<span role='alert'>{formik.errors.password}</span>
</div>
</div>
)}
</div>
{/* end::Form group */}
{/* begin::Action */}
<div className='text-center'>
<button
type='submit'
id='kt_sign_in_submit'
className='btn btn-lg btn-primary w-100 mb-5 '
disabled={formik.isSubmitting || !formik.isValid}
>
{!loading && <span className='indicator-label'>Continue</span>}
{loading && (
<span className='indicator-progress' style={{display: 'block'}}>
Please wait...
<span className='spinner-border spinner-border-sm align-middle ms-2'></span>
</span>
)}
</button>
{/* begin::Separator */}
<div className='text-center text-muted text-uppercase fw-bolder mb-5'>or</div>
{/* end::Separator */}
{/* begin::Google link */}
<a className='btn btn-flex flex-center btn-light btn-lg w-100 mb-5'>
<img
alt='Logo'
src={toAbsoluteUrl('/media/svg/brand-logos/google-icon.svg')}
className='h-20px me-3'
/>
Continue with Google
</a>
{/* end::Google link */}
{/* begin::Google link */}
<a href='#' className='btn btn-flex flex-center btn-light btn-lg w-100 mb-5'>
<img
alt='Logo'
src={toAbsoluteUrl('/media/svg/brand-logos/facebook-4.svg')}
className='h-20px me-3'
/>
Continue with Facebook
</a>
{/* end::Google link */}
{/* begin::Google link */}
<a href='#' className='btn btn-flex flex-center btn-light btn-lg w-100'>
<img
alt='Logo'
src={toAbsoluteUrl('/media/svg/brand-logos/apple-black.svg')}
className='h-20px me-3'
/>
Continue with Apple
</a>
{/* end::Google link */}
</div>
{/* end::Action */}
</form>
)
}
Should firebase be sending back a token or something similar that is saved in the form of a cookie, or am I way off base?
My firebase.js
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import {
GoogleAuthProvider,
getAuth,
signInWithPopup,
signInWithEmailAndPassword,
createUserWithEmailAndPassword,
sendPasswordResetEmail,
signOut,
} from "firebase/auth";
import {
getFirestore,
query,
getDocs,
collection,
where,
addDoc,
} from "firebase/firestore";
const firebaseConfig = {
};
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
const googleProvider = new GoogleAuthProvider();
const signInWithGoogle = async () => {
try {
const res = await signInWithPopup(auth, googleProvider);
const user = res.user;
const q = query(collection(db, "users"), where("uid", "==", user.uid));
const docs = await getDocs(q);
if (docs.docs.length === 0) {
await addDoc(collection(db, "users"), {
uid: user.uid,
name: user.displayName,
authProvider: "google",
email: user.email,
});
}
} catch (err) {
console.error(err);
alert(err.message);
}
};
const logInWithEmailAndPassword = async (email, password) => {
try {
await signInWithEmailAndPassword(auth, email, password);
} catch (err) {
console.error(err);
alert(err.message);
}
};
const registerWithEmailAndPassword = async (name, email, password) => {
try {
const res = await createUserWithEmailAndPassword(auth, email, password);
const user = res.user;
await addDoc(collection(db, "users"), {
uid: user.uid,
name,
authProvider: "local",
email,
});
} catch (err) {
console.error(err);
alert(err.message);
}
};
const sendPasswordReset = async (email) => {
try {
await sendPasswordResetEmail(auth, email);
alert("Password reset link sent!");
} catch (err) {
console.error(err);
alert(err.message);
}
};
const logout = () => {
signOut(auth);
};
export {
auth,
db,
signInWithGoogle,
logInWithEmailAndPassword,
registerWithEmailAndPassword,
sendPasswordReset,
logout,
};
2
Answers
You need to check the return value of this function call
logInWithEmailAndPassword(values.email, values.password)
!Based on the response, you either authenticate the user and save the token that’s sent or do not authenticate the user.
You’ll probably have to show us what’s happening in your
firebase.js
where you’re handling the auth.From what i’m seeing right now, you’re missing the firebase hooks that track your auth state –
getAuth
andonAuthStateChanged
Refer to docs here:
https://firebase.google.com/docs/auth/web/start
https://firebase.google.com/docs/auth/web/manage-users#get_a_users_profile
Example of how you might do it in
firebase.js
Outside of
firebase.js
, for example in your current component:This should be the missing link between firebase and your React side of things – then you can handle it however you need on this side once you’ve connected the dots.