Firebase email verification throws Invalid email link in reactjs - reactjs

I'm trying to implement a firebase email verification process while signup using reactjs in my local. I have implemented the createUserWithEmailAndPassword default function along with the sendEmailVerification function. Once a new user is created, they are getting a confirmation email on their respective mail IDs but if the user tries to verify the email we are getting the below error as a response in signInWithEmailLink. We have tried with SSL in localhost 'https://localhost' but still the same issue.
Error
{code: 'auth/argument-error', message: 'Invalid email link!', a: null}
signin.js
import React, { useRef } from 'react'
import { auth } from '../firebase';
import './Signin.css'
const Signin = () => {
const emailRef = useRef(null);
const passwordRef = useRef(null);
const signUp = e => {
e.preventDefault();
auth.createUserWithEmailAndPassword(
emailRef.current.value,
passwordRef.current.value
).then(userCredential => {
userCredential.user.sendEmailVerification();
console.log(userCredential,'userCredential')
//auth.signOut();
return userCredential;
}).catch(err => {
console.log(err)
})
}
const signIn = e => {
e.preventDefault();
auth.signInWithEmailAndPassword(
emailRef.current.value,
passwordRef.current.value
).then(user => {
console.log(user)
}).catch(err => {
console.log(err)
})
}
const confirm = e =>{
const locationCode = window.location.href;
e.preventDefault();
auth.signInWithEmailLink(emailRef.current.value, locationCode)
.then((result) => {
console.log(result,'result')
})
.catch((err) => {
console.log(err,'err')
});
}
return (
<div className="signin">
<form action="">
<h1>Sign in</h1>
<input ref={emailRef} type="email" />
<input ref={passwordRef} type="password" />
<button onClick={signIn}>Sign in </button>
<button onClick={confirm}>confirm </button>
<h6>Not yet register? <span onClick={signUp} className="signin__link">Sign up</span></h6>
</form>
</div>
)
}
export default Signin

Related

react firebase auth login best practice

I have a question regarding firebase auth best practices. Below is some simple code which handles user login. I want to know after the user logs in, what is the best / most efficient way of storing the user information in React. I have 3 options:
Storing in state the 'user' object which comes back in the .then
Storing in a context the 'user' object which comes back in the .then
Using the auth variable from firebase-config.js which comes with the currentUser object
Thanks
import React, { useState } from "react";
import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "../firebase-config";
import { useNavigate } from "react-router-dom";
const Login = () => {
const [loginEmail, setLoginEmail] = useState("");
const [loginPassword, setLoginPassword] = useState("");
const [currentUser, setCurrentUser] = useState({});
const navigate = useNavigate();
const handleLogin = () => {
signInWithEmailAndPassword(auth, loginEmail, loginPassword)
.then((user) => {
setCurrentUser(user);
navigate("/");
})
.catch((err) => {
console.log(err.code);
err.code === "auth/wrong-password"
? alert("Incorrect password")
: alert(err.code);
});
};
return (
<>
<div className="form-container">
<p>
email
<input
type="email"
onChange={(e) => {
setLoginEmail(e.target.value);
}}
/>
</p>
<p>
password
<input
type="password"
onChange={(e) => {
setLoginPassword(e.target.value);
}}
/>
</p>
<button onClick={handleLogin}>Login</button>
</div>
</>
);
};
export default Login;

Error(Uncaught TypeError): Cannot read properties of undefined (reading 'params')

i am using react-router-dom v6 this code generating above error message ..please help me to solve the error ... backend is working fine ..i think this error is coming from fronted .... it works with postman ..
i am following a older tutorial ... now i installed new version of react-router-dom ... please help me out
this is ResetPassword.js file
import React, { Fragment, useState, useEffect } from "react";
import "./ResetPassword.css";
import Loader from "../layout/Loader/Loader";
import { useDispatch, useSelector } from "react-redux";
import { clearErrors, resetPassword } from "../../actions/userAction";
import { useAlert } from "react-alert";
import MetaData from "../layout/MetaData";
import LockOpenIcon from "#material-ui/icons/LockOpen";
import LockIcon from "#material-ui/icons/Lock";
const ResetPassword = ({ history, match }) => {
const dispatch = useDispatch();
const alert = useAlert();
const { error, success, loading } = useSelector(
(state) => state.forgotPassword
);
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const resetPasswordSubmit = (e) => {
e.preventDefault();
const myForm = new FormData();
myForm.set("password", password);
myForm.set("confirmPassword", confirmPassword);
dispatch(resetPassword(match.params.token, myForm));
};
useEffect(() => {
if (error) {
alert.error(error);
dispatch(clearErrors());
}
if (success) {
alert.success("Password Updated Successfully");
history.push("/login");
}
}, [dispatch, error, alert, history, success]);
return (
<Fragment>
{loading ? (
<Loader />
) : (
<Fragment>
<MetaData title="Change Password" />
<div className="resetPasswordContainer">
<div className="resetPasswordBox">
<h2 className="resetPasswordHeading">Update Profile</h2>
<form
className="resetPasswordForm"
onSubmit={resetPasswordSubmit}
>
<div>
<LockOpenIcon />
<input
type="password"
placeholder="New Password"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<div className="loginPassword">
<LockIcon />
<input
type="password"
placeholder="Confirm Password"
required
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
/>
</div>
<input
type="submit"
value="Update"
className="resetPasswordBtn"
/>
</form>
</div>
</div>
</Fragment>
)}
</Fragment>
);
};
export default ResetPassword;
And The backend code is here
export const resetPassword = (token, passwords) => async (dispatch) => {
try {
dispatch({ type: RESET_PASSWORD_REQUEST });
const config = { headers: { "Content-Type": "application/json" } };
const { data } = await axios.put(
`/api/v1/password/reset/${token}`,
passwords,
config
);
dispatch({ type: RESET_PASSWORD_SUCCESS, payload: data.success });
} catch (error) {
dispatch({
type: RESET_PASSWORD_FAIL,
payload: error.response.data.message,
});
}
};
Thank you
In react-router-dom#6 the Route component API changed significantly. There are no longer any route props (i.e. no match or history props) all replaced by React hooks. The history object was replaced by a navigate function via the useNavigate hook, and route path params are accessible via the useParams hook.
Example:
import { useNavigate, useParams } from 'react-router-dom';
const ResetPassword = () => {
const navigate = useNavigate(); // <-- access navigate function
const { token } = useParams(); // <-- access token path parameter
...
const resetPasswordSubmit = (e) => {
...
dispatch(resetPassword(token, myForm)); // <-- use token param here
};
useEffect(() => {
...
if (success) {
alert.success("Password Updated Successfully");
navigate("/login"); // <-- call navigate here
}
}, [dispatch, error, alert, navigate, success]);

Got Received number of calls: 0 error for login functionality

I am writing unit test case for login.
I am unsure about how to test handle submit as it contains one of the service call in the form of getToken() method, it would be greate if someone can guide me through how to handle this situation.
export const getToken = (credentials) => {
const token = 'abccss';
if (
credentials.username === 'test#test.com' &&
credentials.password === '123'
) {
return token;
} else {
return null;
}
};
The above code fetches user name and password and sends it to login in handleSubmit() function
//all imports(loginservice,auth etc etc)
import './Login.scss';
const Login = () => {
const [email, setEmail] = useState('');
const [pwd, setPwd] = useState('');
const authCon = useContext(AuthContext);
const handleSubmit = (e) => {
e.preventDefault();
const token = getToken({ username: email, password: pwd });
if (token) {
authCon.login(token);
window.location.href = '/dashboard';
}
};
return (
<div className="div-login">
<div className="div-login-logo">
<img src={logo} alt="Logo"></img>
</div>
<div>
<form onSubmit={handleSubmit}>
<input
className="credentials-input"
type="email"
value={email}
placeholder="Email Address"
required
onChange={(e) => setEmail(e.target.value)}
/>
<input
className="credentials-input"
type="password"
value={pwd}
placeholder="Password"
required
onChange={(e) => setPwd(e.target.value)}
/>
<button className="login-button" type="submit">
Log In
</button>
</form>
</div>
</div>
);
};
export default Login;
Test Code
test('Submit shoud work successfully', () => {
const mockLogin = jest.fn();
const { getByRole } = render(<Login handleSubmit={mockLogin} />);
const login_button = getByRole('button');
fireEvent.submit(login_button);
expect(mockLogin).toHaveBeenCalledTimes(1);
});
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
As I am new to React, help will be appreciated.
The actual issue is handleSubmit is not a props of Login component.
Also you can't test the internal methods of a component using React testing Library, you have to move the handleSubmit method to either parent component or a common file and pass it to the login component or import it so that you can mock the method and perform the test.
Move the getToken and handleSubmit to a common file like below,
common.ts
export const getToken = (credentials:any) => {
const token = 'abccss';
if (
credentials.username === 'test#test.com' &&
credentials.password === '123'
) {
return token;
} else {
return null;
}
};
export const handleSubmit = (e:any, email:string, pwd: string) => {
e.preventDefault();
const token = getToken({ username: email, password: pwd });
if (token) {
// authCon.login(token);
window.location.href = '/dashboard';
}
};
Modify Login.ts as like below ( see below handleSubmit is not internal and its imported from common.ts file so we that we can mock it)
import React, { useContext, useState } from 'react';
import { getToken, handleSubmit } from './common';
const Login = () => {
const [email, setEmail] = useState('');
const [pwd, setPwd] = useState('');
// const authCon = useContext(AuthContext);
return (
<div className="div-login">
<div className="div-login-logo">
{/* <img src={logo} alt="Logo"></img> */}
</div>
<div>
<form onSubmit={(e) => handleSubmit(e, email, pwd)}>
<input
className="credentials-input"
type="email"
value={email}
placeholder="Email Address"
required
onChange={(e) => setEmail(e.target.value)}
/>
<input
className="credentials-input"
type="password"
value={pwd}
placeholder="Password"
required
onChange={(e) => setPwd(e.target.value)}
/>
<button className="login-button" type="submit">
Log In
</button>
</form>
</div>
</div>
);
};
export default Login;
And finally Login.test.tsx shown below
import { fireEvent, render, screen } from '#testing-library/react';
import Login from './Login';
import * as CommonModule from './common';
jest.mock('./common');
test('Submit shoud work successfully', () => {
const mockLogin = jest.spyOn(CommonModule,'handleSubmit').mockImplementation();
const { getByRole } = render(<Login />);
const login_button = getByRole('button');
fireEvent.submit(login_button);
expect(mockLogin).toHaveBeenCalledTimes(1);
});
Test Result :

How to POST request using axios with React Hooks?

This is my Signupcomponent
const SignupComponent = () => {
const [values, setValues] = useState({
username: 'silvio1',
name: 'Silvioo',
email: 'berlusconi#gmail.com',
password: '123ooo007',
});
const [loading, setLoading] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
const { username, name, email, password } = values;
const user = {username, name, email, password};
await axios.post('${API)/signup', user);
};
const handleChange = name => e => {
setValues({ ...values, [name]: e.target.value });
};
const showLoading = () => (loading ? <div className="alert alert-info">Loading...</div> : '');
const signupForm = () => {
return (
<form onSubmit={handleSubmit}>
<div className="form-group">
<input
value={values.username}
onChange={handleChange('username')}
type="text"
className="form-control"
placeholder="Type your username"
/>
</div>
<div className="form-group">
<input
value={values.name}
onChange={handleChange('name')}
type="text"
className="form-control"
placeholder="Type your name"
/>
</div>
<div className="form-group">
<input
value={values.email}
onChange={handleChange('email')}
type="email"
className="form-control"
placeholder="Type your email"
/>
</div>
<div className="form-group">
<input
value={values.password}
onChange={handleChange('password')}
type="password"
className="form-control"
placeholder="Type your password"
/>
</div>
<div>
<button className="btn btn-primary">Signup</button>
</div>
</form>
);
};
return <React.Fragment>
{showLoading()}
{signupForm()}
</React.Fragment>;
};
export default SignupComponent;
EDIT
I changed my code(zhulien's accepted answer).
Signup page appears,I try to sign up user.
I got error
Unhandled Runtime Error
Error: Request failed with status code 404
Call Stack
createError
node_modules/axios/lib/core/createError.js (16:0)
settle
node_modules/axios/lib/core/settle.js (17:0)
XMLHttpRequest.handleLoad
node_modules/axios/lib/adapters/xhr.js (62:0)
Frontend folder
components
config.js
next.config.js
node_modules
package.json
package-lock.json
pages
My pages folder
_document.js
index.js
signin.js
signup.js
signup.js imports the code above
import Link from 'next/link';
import Layout from '../components/Layout';
import SignupComponent from '../components/frontauth/SignupComponent';
const Signup = () => {
return (
<Layout>
<h2>Signup page</h2>
<SignupComponent />
</Layout>
);
};
My next.config.js
{
APP_NAME: 'BLOG FRONTEND',
APP_DEVELOPMENT: 'http://localhost:3000',
PRODUCTION: false
}
And config.js
const { publicRuntimeConfig } = getConfig();
console.log(publicRuntimeConfig);
export const API = publicRuntimeConfig.PRODUCTION
? 'https://cryptoblog.com'
: 'http://localhost:3000';
export const APP_NAME = publicRuntimeConfig.APP_NAME;
I am new to React and React Hooks. How to solve this problem?
First of all, you're trying to access {username}(which doesn't exist) instead of the state property which is values.username. Furthermore, don't use hooks in event handlers, they should be used in the top level body of the component or in custom hooks only. Checkout this: React hooks rules.
So:
In your form you have to use the state(values) properties.
Extract useEffect hook in the main body flow of the component or BETTER remove it altogether as you're not using it properly currently. You're better of with just the simple event handler for form submit which should post the data somewhere without setting any state.
Your code could look something like:
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import { API } from '../../config';
const SignupComponent = () => {
const [values, setValues] = useState({
username: 'silvio1',
name: 'Silvioo',
email: 'berlusconi#gmail.com',
password: '123ooo007',
});
const [loading, setLoading] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
const { username, name, email, password } = values;
const user = {username, name, email, password};
await axios.post('${API)/signup', user);
};
const handleChange = name => e => {
setValues({ ...values, [name]: e.target.value });
};
const showLoading = () => (loading ? <div className="alert alert-info">Loading...</div> : '');
const signupForm = () => {
return (
<form onSubmit={handleSubmit}>
<div className="form-group">
<input
value={values.username}
onChange={handleChange('username')}
type="text"
className="form-control"
placeholder="Type your username"
/>
</div>
this is how it should be:
useEffect(() => {
postUser();
}, []);
not inside the function the way you have done it:
const handleSubmit = e => {
e.preventDefault();
setValues({...values});
const { username, name, email, password } = values;
const user = {username, name, email, password};
async function postUser () {
const result = await axios.post('${API)/signup', user);
};
useEffect(() => {
postUser();
}, []);
};
UseEffects aren't meant to be placed inside your functions.Just place them inside your functional component,with some value(or no value) inside your dependency array of the useEffect.These values present inside the array will trigger the useEffect whenever they get changed.

Reset Password in React

i am creating a mern app. i got stuck in forgot password. i'm able to send a mail for forgot password but when i try to set new password it is not changing password but in postman i was able to change the password but when it comes to react i was not. I know the problem is that i was not able to get token as params .
work in postman but not in when i try in react.
Resetpassword component
import React, { Fragment, useState } from 'react';
import { connect } from 'react-redux';
import { Link, Redirect } from 'react-router-dom';
import { setAlert } from '../../actions/alert';
import { reset } from '../../actions/auth';
import PropTypes from 'prop-types';
const Reset = ({ setAlert, reset }) => {
const [formData, setFormData] = useState({
password: '',
password2: ''
});
const { password, password2 } = formData;
const onChange = e =>
setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = async => {
const token = props.match.params.token;
console.log(token);
if (password !== password2) {
setAlert('password does not matched', 'danger');
} else {
reset({ password, token });
}
};
return (
<Fragment>
<section className='container'>
<h1 className='large text-primary'>RESET PASSWORD</h1>
<p className='lead'>
<i className='fas fa-user' /> Create Your NEW PASSWORD
</p>
<form
className='form'
onSubmit={e => onSubmit(e)}
action='create-profile.html'
>
<div className='form-group'>
<input
type='password'
placeholder='Password'
name='password'
value={password}
onChange={e => onChange(e)}
/>
</div>
<div className='form-group'>
<input
type='password'
placeholder='Confirm Password'
name='password2'
value={password2}
onChange={e => onChange(e)}
/>
</div>
<input type='submit' className='btn btn-primary' value='Register' />
</form>
<p className='my-1'>
Already have an account? <Link to='/login'>Sign In</Link>
</p>
</section>
</Fragment>
);
};
Reset.propTypes = {
setAlert: PropTypes.func.isRequired,
reset: PropTypes.func.isRequired
};
export default connect(
null,
{ setAlert, reset }
)(Reset);
resetaction.JS
export const reset = ({ password, token }) => async dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
};
const body = JSON.stringify({ password, token });
try {
const res = await axios.put(
`http://localhost:3000/api/auth/reset/${token}`,
body,
config
);
dispatch({
type: RESET_PASSWORD,
payload: res.data
});
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
}
};
By only seeing this snippet I assume your problems are following lines:
const Reset = ({ setAlert, reset }) => {
//...
const token = props.match.params.token;
You destructed the whole props argument (into { setAlert, reset }), so in your case props is undefined. You should adapt your code to this:
const Reset = ({ setAlert, reset, match }) => {
//...
const token = match.params.tok

Resources