Wrong authentication Login in ReactJS - reactjs

I am trying to do a Login page. So I have also protected route which is an admin page. So the first page is Login and if the user is successfully logged in, it should be redirect to '/admin'. For this, my Login component is:
import React, { useState, useEffect } from "react";
import Axios from "axios";
import useForm from "../components/LoginForm/useForm";
import validate from "components/LoginForm/validate";
import redtruck from "../assets/img/red-truck.png";
import auth from "../Authentication/auth";
import { withRouter } from "react-router";
const Login = ({ submitForm, history }) => {
const [isSubmitted, setIsSubmitted] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [login, setLogin] = useState(false);
async function submitForm() {
setIsSubmitted(true);
try {
await fetchLogin(values.email, values.password);
auth.login(() => {
history.push("/admin");
});
} catch (e) {
console.log("wrong pass");
}
}
const { handleChange, values, handleSubmit, errors } = useForm(
submitForm,
validate
);
useEffect(() => {
if (localStorage.getItem("user-info")) {
submitForm();
}
}, []);
const fetchLogin = async (email, password) => {
try {
setLoading(true);
const res = await Axios({
method: "POST",
url: `url`,
headers: {
},
data: {
user_email: email,
user_password: password,
},
});
if (res.status === 200) {
setLogin(true);
localStorage.setItem("user-info", JSON.stringify(res.data));
}
setLoading(false);
} catch (err) {
setError(err.message);
setLoading(false);
}
};
return (
<>
<div>
<div className="form-container">
<div className="form-content-left">
<img className="form-img" src={redtruck} alt="spaceship" />
</div>
<div className="form-content-right">
<h1>SIGN IN</h1>
<form className="form" onSubmit={handleSubmit}>
<div className="form-inputs">
<label htmlFor="email" className="form-label">
Email address
</label>
<input
id="signin-email"
type="email"
name="email"
placeholder="Enter email"
className="form-input"
value={values.email}
onChange={handleChange}
/>
{errors.email && <p>{errors.email}</p>}
</div>
<div className="form-inputs">
<label htmlFor="password" className="form-label">
Password
</label>
<input
id="signin-password"
type="password"
name="password"
placeholder="Password"
className="form-input"
value={values.password}
onChange={handleChange}
/>
{errors.password && <p>{errors.password}</p>}
{login ? "" : <p>The password or the email is wrong</p>}
</div>
<button
variant="primary"
type="submit"
className="form-input-btn"
>
LOGIN
</button>
</form>
</div>
</div>
</div>
</>
);
};
export default withRouter(Login);
So, my problem is even though the password or the email is wrong, it is still redirecting to '/admin'. So, I dont want it to redirect to the page '/admin' when the credentials are wrong but also I want to show error message if the password or email is wrong. If you could give me any suggestion on this, I will be really glad.
Thanks...

You should only use the onSubmit callback from the form.
At the moment, you are calling the handleSubmit and loginButton functions when the user clicks login. Remove the loginButton callback and execute your logic in the onSubmit callback from the form. Also be sure to event.preventDefault() at the beginning of the form callback.
If your button has type="submit", it will submit the form automatically.
The submitForm function should looks something like this:
async function submitForm() {
setIsSubmitted(true);
try {
await fetchLogin();
auth.login(() => {
history.push("/admin");
});
} catch (e) {
// User is not logged
}
}
And just throw in the fetchLogin function if the login fails

You should either use loginButton() or submitForm() to handle the login.

Use e.preventDefault() default like this to prevent auto submit. Use the Button Click to Submit the form.
You can use Button Click Event and Remove form submit.
<button
variant="primary"
type="submit"
className="form-input-btn"
onClick={handleLoginSubmit}
>
LOGIN
</button>
const handleLoginSubmit = async (event) => {
event.preventDefault();
setIsSubmitted(true);
try {
await fetchLogin(values.email, values.password);
auth.login(() => {
history.push("/admin");
});
} catch (e) {
console.log("wrong pass");
}
}

Related

How to not give user access to the login page when they are already logged in?

https://pastebin.com/mXgqRP4j
I am trying to implement that when a user is logged in, the user has no access to the login page. To do that I have put an if condition at the end that if the user is authenticated, the user will be redirected to the dashboard even when they input the path to the login component. But whats happening is that when I input the link to the login page (I have routes set up), the login page shows up for a split second and then disappears and then the dashboard appears. What should have happened was that the user shouldve been redirected directly to the dashboard. Please guide me!
import { useEffect, useState } from "react"
import Admin from "../../pages/Admin"
import { Navigate } from "react-router-dom";
import { useNavigate } from "react-router-dom";
function AdminLogin() {
const navigate = useNavigate()
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [csrf, setCsrf] = useState('')
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
function getCsrf(){
fetch("http://localhost:8000/csrf/", {
credentials: "include",
})
.then((res) => {
let csrfToken = res.headers.get("X-CSRFToken");
setCsrf({csrf: csrfToken});
})
.catch((err) => {
console.log(err);
})
}
const login = (event) => {
event.preventDefault();
fetch("http://localhost:8000/login/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": csrf.csrf,
},
credentials: "include",
body: JSON.stringify({username: username, password: password}),
})
.then(isResponseOk)
.then((data) => {
console.log(data);
setIsAuthenticated(true)
localStorage.setItem("authenticated", true);
setUsername('')
setPassword('')
// this.setState({isAuthenticated: true, username: "", password: ""});
})
.catch((err) => {
console.log('inside login catch')
console.log(csrf.csrf, 'catch')
console.log(err);
});
}
const isResponseOk = (response) =>{
if (response.status >= 200 && response.status <= 299) {
return response.json();
} else {
console.log(response)
throw Error(response.statusText);
}
}
useEffect(() => {
//getSessions
fetch("http://localhost:8000/session/", {
credentials: "include",
})
.then((res) => res.json())
.then((data) => {
// console.log(data);
if (data.isAuthenticated) {
setIsAuthenticated(true)
console.log(data)
} else {
setIsAuthenticated(false)
console.log(data)
getCsrf()
}})
.catch((err) => {
console.log(err);
});
}, [])
console.log(csrf);
console.log(counter)
const handleUsername = (e) => {
setUsername(e.target.value)
}
const handlePassword = (e) => {
setPassword(e.target.value)
}
const loginScreen = (
<div className="login-box m-auto">
<div className="card">
<div className="card-body login-card-body">
<p className="login-box-msg">Sign in to start your session</p>
<form method="post" onSubmit={login}>
<div className="input-group mb-3">
<input required type="text" value={username} onChange={handleUsername} className="form-control" placeholder="Username" />
<div className="input-group-append">
<div className="input-group-text">
<span className="fas fa-envelope" />
</div>
</div>
</div>
<div className="input-group mb-3">
<input required type="password" value={password} onChange={handlePassword} className="form-control" placeholder="Password" />
<div className="input-group-append">
<div className="input-group-text">
<span className="fas fa-lock" />
</div>
</div>
</div>
<div className="row">
<div className="col-4">
<button type="submit" className="btn btn-primary btn-block">Sign In</button>
</div>
</div>
</form>
</div>
</div>
</div>)
if(isAuthenticated)
{
return <Navigate replace to="/admin/dashboard" />;
}
else{
return loginScreen
}
}
You can create isLoading state alongside isAuthenticated state and initialize it with true and show the loading screen until checking authentication is finished and set isLoading to false. After that you can show the login screen only if isLoading is false and isAuthentcated is also false.
If it's okay to use Redux so I suggest using Redux-Persist and make it rehydrate the auth part so you will not face this issue.

my form won't refresh back to initial state or navigate to the feeds page after success full registration i'm i wrong using async?

my form won't refresh back to initial state or navigate to the feeds page after success full registration and now react is telling me Async await is only available in es8 please can i go about this i want the form to provide some kind of feedback after registration like to n avigate to the homepage and clear all field but it's not working
import { Link, useNavigate } from 'react-router-dom'
import { toast } from 'react-toastify'
import {
getAuth,
createUserWithEmailAndPassword,
updateProfile,
} from 'firebase/auth'
import { setDoc, doc, serverTimestamp } from 'firebase/firestore'
import { db } from '../firebase.config'
import OAuth from '../components/OAuth'
function SignUp() {
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
})
const { name, email, password } = formData
const navigate = useNavigate()
const onChange = (e) => {
setFormData((prevState) => ({
...prevState,
[e.target.id]: e.target.value,
}))
}
const onSubmit = async (e) => {
e.preventDefault()
try {
const auth = getAuth()
const userCredential = await createUserWithEmailAndPassword(
auth,
email,
password
)
const user = userCredential.user
updateProfile(auth.currentUser, {
displayName: name,
})
const formDataCopy = { ...formData }
delete formDataCopy.password
formDataCopy.timestamp = serverTimestamp()
await setDoc(doc(db, 'users', user.uid), formDataCopy)
navigate('/')
} catch (error) {
toast.error('Something went wrong with registration')
}
}
return (
<>
<div className='pageContainer'>
<header>
<p className='pageHeader'>Welcome Back!</p>
</header>
<form onSubmit={onSubmit}>
<input
type='text'
className='nameInput'
placeholder='Name'
id='name'
value={name}
onChange={onChange}
/>
<input
type='email'
className='emailInput'
placeholder='Email'
id='email'
value={email}
onChange={onChange}
/>
<div className='passwordInputDiv'>
<input
type='password'
className='passwordInput'
placeholder='Password'
id='password'
value={password}
onChange={onChange}
/>
</div>
<Link to='/forgot-password' className='forgotPasswordLink'>
Forgot Password
</Link>
<div className='signUpBar'>
<p className='signUpText'>Sign Up</p>
<button className='signUpButton'>
Sign Up
</button>
</div>
</form>
<OAuth />
<Link to='/sign-in' className='registerLink'>
Sign In Instead
</Link>
</div>
</>
)
}
export default SignUp

Cannot register. Username and password did not pass in the payload when using useRef

I tried to pass the username and password input by using useRef() for the registration process through the register form. After click button to submit it, it said required username and password. I check the network payload at browser, it only contain email without username and password.
Below are the code
import { useRef, useState } from "react";
import "./register.scss";
import axios from "axios";
import { useNavigate } from "react-router-dom";
const Register = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [username, setUsername] = useState("");
const navigate = useNavigate();
const emailRef = useRef();
const passwordRef = useRef();
const usernameRef = useRef();
// Send email to appear password
const handleStart = () => {
setEmail(emailRef.current.value);
};
// Send username & password for membership
const handleFinish = async (e) => {
e.preventDefault();
setPassword(passwordRef.current.value);
setUsername(usernameRef.current.value);
try {
await axios.post("auth/register", { username, email, password });
navigate("/login");
} catch (err) {
console.log(err);
}
};
return (
<div className="register">
<div className="wrapper">
<div className="header">
<img src="./assets/logo.png" alt="" className="logo" />
<button className="login-btn">Sign In</button>
</div>
</div>
<div className="container">
<h1>Unlimited movies, TV shows and more</h1>
<h2>Watch anywhere. Cancel anytime.</h2>
<p>
Ready to watch? Enter your email to create or restart your membership.
</p>
{!email ? (
<div className="input">
<input type="email" placeholder="Email address" ref={emailRef} />
<button className="register-btn" onClick={handleStart}>
Get Started
</button>
</div>
) : (
<form className="input">
<input type="username" placeholder="Username" ref={usernameRef} />
<input type="password" placeholder="Password" ref={passwordRef} />
<button className="register-btn" onClick={handleFinish}>
Start
</button>
</form>
)}
</div>
</div>
);
};
export default Register;
Here are the screenshot for network payload
Payload
[Preview2
You're trying to access state that hasn't update yet.
If you're using refs, you can remove the useState hooks and change your code to something like below.
const handleFinish = async (e) => {
e.preventDefault();
try {
await axios.post("auth/register", { username: usernameRef.current.value , email: emailRef.current.value, password: passwordRef.current.value });
navigate("/login");
} catch (err) {
console.log(err);
}
Controlled components would be a better option for handling form elements imo.
https://reactjs.org/docs/forms.html#controlled-components

React 'load' is not defined no-undef

I'm trying to implement Netlify identity with React here, using this guide
But, I get the error 'load' is not defined no-undef
It is referring to this line
load(loginUser(email, password, true))
Here is the code:
import React, { useRef, useLayoutEffect } from 'react';
import { useIdentityContext } from 'react-netlify-identity';
import { navigate } from "#reach/router" // from login tutorial
// log in/sign up example
function Login() {
const { loginUser, signupUser } = useIdentityContext();
const formRef = React.useRef();
const [msg, setMsg] = React.useState('');
const signup = () => {
const email = formRef.current.email.value;
const password = formRef.current.password.value;
signupUser(email, password)
.then(user => {
console.log('Success! Signed up', user);
navigate('/dashboard');
})
.catch(err => console.error(err) || setMsg('Error: ' + err.message));
};
return (
<form
ref={formRef}
onSubmit={e => {
e.preventDefault();
const email = e.target.email.value;
const password = e.target.password.value;
load(loginUser(email, password, true))
.then(user => {
console.log('Success! Logged in', user);
navigate('/dashboard');
})
.catch(err => console.error(err) || setMsg('Error: ' + err.message));
}}
>
<div>
<label>
Email:
<input type="email" name="email" />
</label>
</div>
<div>
<label>
Password:
<input type="password" name="password" />
</label>
</div>
<div>
<input type="submit" value="Log in" />
<button onClick={signup}>Sign Up </button>
{msg && <pre>{msg}</pre>}
</div>
</form>
);
}
export default Login;

Two times click is necessary to Login in ReactJS

I am trying to make a Login page and I am successful in some way. So here is my Login component:
import React, { useState, useEffect } from "react";
import Axios from "axios";
import useForm from "../components/LoginForm/useForm";
import validate from "components/LoginForm/validate";
import redtruck from "../assets/img/red-truck.png";
import auth from "../Authentication/auth";
import { withRouter } from "react-router";
const Login = ({ submitForm, history }) => {
const [isSubmitted, setIsSubmitted] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [login, setLogin] = useState(false);
async function submitForm() {
setIsSubmitted(true);
try {
await fetchLogin(values.email, values.password);
if(login){
auth.login(() => {
history.push("/admin");
});
}
} catch (e) {
auth.login(() => {
history.push("/");
})
}
}
const { handleChange, values, handleSubmit, errors } = useForm(
submitForm,
validate
);
useEffect(() => {
if (localStorage.getItem("user-info")) {
submitForm();
}
}, []);
const fetchLogin = async (email, password) => {
try {
setLoading(true);
const res = await Axios({
method: "POST",
url: `url`,
headers: {
},
data: {
user_email: email,
user_password: password,
},
});
if (res.status === 200) {
setLogin(true);
localStorage.setItem("user-info", JSON.stringify(res.data));
}
setLoading(false);
} catch (err) {
setError(err.message);
setLoading(false);
}
};
return (
<>
<div>
<div className="form-container">
<div className="form-content-left">
<img className="form-img" src={redtruck} alt="spaceship" />
</div>
<div className="form-content-right">
<h1>SIGN IN</h1>
<form className="form" onSubmit={handleSubmit}>
<div className="form-inputs">
<label htmlFor="email" className="form-label">
Email address
</label>
<input
id="signin-email"
type="email"
name="email"
placeholder="Enter email"
className="form-input"
value={values.email}
onChange={handleChange}
/>
{errors.email && <p>{errors.email}</p>}
</div>
<div className="form-inputs">
<label htmlFor="password" className="form-label">
Password
</label>
<input
id="signin-password"
type="password"
name="password"
placeholder="Password"
className="form-input"
value={values.password}
onChange={handleChange}
/>
{errors.password && <p>{errors.password}</p>}
{login ? "" : <p>The password or the email is wrong</p>}
</div>
<button
variant="primary"
type="submit"
className="form-input-btn"
>
LOGIN
</button>
</form>
</div>
</div>
</div>
</>
);
};
export default withRouter(Login);
So the login state is set to true when email and password are right for the user. Later I want to use it when redirecting page to "/admin". But my problem is I have to click twice to login in the first place. Besides I am not sure, if the catch part is right:
catch (e) {
auth.login(() => {
history.push("/");
})
}
So I would be really glad, if you can give me some hint about it.
Thanks...
it is not that you have to press twice, you can check component state, sometimes React batches setState and then update value. You can look at this setState doesn't update the state immediately

Resources