AXIOS Status 400 Bad Request on React Front End - reactjs

I am building an authentication component on React.
When the wrong password/username is entered, I am expecting a Status 400 with the message: 'Invalid email or password' on the front end
Instead, I am getting Status 400 with the message: 'Request failed with status code 400'. I used postman to simulate a bad login and I do get the message : 'Invalid email or password'
When I tried a successful login on my frontend, everything works and I get a JWT token.
I also did a console.log on the backend and I can see that the data did reach the backend. The problem seems to be that the error is not handled by the front end properly.
Can someone take a look and let me know what is the problem? thank you.
Backend Post routes
router.post('/signin', async (req, res) => {
console.log(req.body)
let user = await User.findOne({ email: req.body.email })
if (!user) return res.status(400).send('Invalid email or password')
//compare the password with the password in database
const validPassword = await bcrypt.compare(req.body.password, user.password)
if (!validPassword) return res.status(400).send('Invalid email or password')
const token = user.generateAuthToken()
// res.send(token)
res.header('x-auth-token', token).send(_.pick(user, ['_id', 'name)', 'email']))
})
Frontend React
doSubmit = async (e) => {
e.preventDefault()
const { data } = this.state
try {
console.log(data)
await userService.signIn(data)
} catch (ex) {
console.log(ex.message)
if (ex && ex.response.status === 400) {
let errors = { ...this.state.errors }
errors.email = ex.message
this.setState({errors})
}
}
}
userService
import axios from 'axios'
import { SIGN_UP, SIGN_IN } from '../Components/constant/constant';
import { Redirect } from 'react-router-dom';
export default {
register: (user) => {
console.log(user, 'axios')
axios.post(SIGN_UP, {
email: user.email,
password: user.password,
name: user.name
}).then(function (response) {
console.log(response, 'response')
console.log(response)
if (response.status === 200) {
window.location = '/signupsuccessful'
}
})
.catch(function (error) {
console.log(error);
})
},
signIn: async (data) => {
console.log('sign in user service')
await axios.post(SIGN_IN, {
email: data.email,
password: data.password,
})
}
}

I think you just missed the response part of the exception in the doSubmit function of the React code, so you get the exception message and not the response message from the request.
Change
errors.email = ex.message
To
errors.email = ex.response.data
Example
if (ex && ex.response.status === 400) {
let errors = { ...this.state.errors }
errors.email = ex.response.data
this.setState({errors})
}

Nothing is wrong in your code just to get the response from the error case in axios you have to get like so:
...
.catch((error)=>console.log(error.response.data))
EDIT: for more details
So what you have to do in your code is:
Backend
don't send a string i recommend
send a json
res.status(400).send({message:'Invalid email or password'})
FrontEnd
if (ex && ex.response.status === 400) {
let errors = { ...this.state.errors }
errors.email = ex.response.data.message
this.setState({errors})
}

Related

Why am I getting a 405 error in production but not development?

This is the first project I've built from scratch and first time deploying anything with AWS, ubuntu, nginx. The app is built with postgres, express/node, and react.
When I click the login button in production, I get this error: POST http://18.216.221.221/dashboard/api/1/login 405 (Not Allowed)
But in development the POST request works fine and goes to http://localhost:5000/api/1/login
I can't figure out why in production it's adding the "dashboard" to the URL.
This is the server route:
app.post('/api/1/login', async (req, res)=>{
if (!req.body.username || !req.body.password) {
return res.status(400).json('missing fields')
}
try {
const result = await db.query("select * from login where username = $1", [req.body.username])
const isValid = bcrypt.compareSync(req.body.password, result.rows[0].hash);
if (isValid) {
res.status(200).json({
status: 'login successful',
data: {
user: result.rows[0].username
}
})
} else {
res.status(400).json({
status: 'login failed'
})
}
} catch(error) {
console.log('unable to login')
}
})
And this is the function for handling the login:
const handleLogin = async (e) => {
e.preventDefault()
try {
const response = await ClientFilesApi.post(`/login`, {
username,
password
})
console.log(response)
if (response.data.data.user === 'myemail') {
setUserLoggedIn(true)
setPassword("")
history.push(`/dashboard`)
}
} catch (err) {
console.log(err)
}
}
I've set my api baseURL like this:
const baseURL = process.env.NODE_ENV === 'production' ? "api/1" : "http://localhost:5000/api/1"
export default axios.create({
baseURL
})
I've followed all the instructions for deploying from this tutorial:
https://github.com/Sanjeev-Thiyagarajan/PERN-STACK-DEPLOYMENT
And this is my source code:
https://github.com/cipdv/ciprmt

How can I properly handle request errors with React front end?

Currently I have my backend set up as such on the '/register' route:
registerRouter.post('/', async (req, res) => {
// Validate submitted registration form
const { error } = registerValidation(req.body)
if(error) {
return res.status(400).send(error.details[0].message)
}
try {
// Check if email exists already
const user = await User.findOne({ email: req.body.email })
if(user) {
return res.status(400).send('Email already exists')
}
// If not, begin registering user by hashing the password
const hashedPassword = await bcrypt.hash(req.body.password, 10)
const newUser = new User({
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
password: hashedPassword
})
const savedUser = await newUser.save()
res.send(savedUser)
} catch(error) {
res.sendStatus(500)
}
})
Using Postman I get the proper responses when I make correct/incorrect requests. But when I make requests on my frontend, if it is an incorrect request, e.g. not long enough password, missing a required field, then I just get a 400 response. How can I use the error response to, for example, display the error on-screen for the user to see?
This is my current onSubmit function for the form:
const register = async event => {
event.preventDefault()
axios
.post('/register', newUser)
.then(res => console.log(res))
.catch(err => console.log(err))
}
try to use:
axios
.post('/register', newUser)
.catch(function (error) {
console.log(error.toJSON()); // or maybe exist .toText()
});
(https://github.com/axios/axios#handling-errors)
also convert it on server side:
return res.status(400).send('Email already exists')
to
return res.status(400).send({ error: 'Email already exists' });

Error message from server side is not displaying in front end

When login gets failed in server side res.status(403).json({ fail: "Login failed" }); message from server side is passing into front end setHelperText(failMessage); How can i get the 'Login Failed' message in front end ?
It is displaying error in chrome console >> Error: Request failed with status code 403
at createError (createError.js:16)
at settle (settle.js:17)
server.js
app.post('/service/login', async (req, res) => {
try {
const userEmail = req.body.email;
const userPassword = req.body.password;
const loginData = await UserModel.findAll({ where: { email: userEmail} });
const password = loginData[0].password;
const email = loginData[0].email;
if(password === userPassword && email === userEmail){
const privilege = loginData[0].privilege;
res.status(200).json({ success: true, privilege, email });
}else{
res.status(403).json({ fail: "Login failed" });
}
} catch (e) {
res.status(500).json({ message: e.message });
}
});
Login.js
const fetchData = async () => {
try {
const res = await axios.post('http://localhost:8000/service/login', { email , password });
console.log("Front End success message:"+res.data.success);
if(res.data.success){
setHelperText("Login successfully");
setValue(res.data.privilege);
setError(true);
}
else{
const failMessage = res.data.fail;
setHelperText(failMessage);
}
} catch (e) {
console.log(e);
}
}
If the response is not success, (403 in your case), catch block will be executed, so move your logic inside the else block to catch block in the Login.js
catch(e) {
const failMessage = e.response.data.fail;
setHelperText(failMessage);
// console.log(e.data.response); -> to print the server response
}

Cookie being passed to client, but not being saved in browser

I am getting cookie in Network as shown in below screen
but in browser this is showing blank
Front-end Code REACT
signIn: (username, password) =>
axios
.post('http://127.0.0.1:5000/login', {
data: {
Username: username,
Password: password,
},
})
.then(response => {
if (response.status === 200) {
console.log('sign in response', response);
return response;
}
})
.catch(error => {
if (error.response && error.response.status === 400) {
return error;
}
throw error;
}),
};
axios.defaults.withCredentials = true;
BACKEND CODE
username = request.json['data']['Username']
password = request.json['data']['Password']
try:
u = Cognito(COGNITO_USER_POOL_ID, COGNITO_CLIENT_ID, username=username)
u.authenticate(password=password)
resp = make_success_resp({'username': u.username})
# 31557600 sec in 1 year
resp.set_cookie('ATOK',str(u.access_token),max_age=60*60*24*365*2, domain= 'app.localhost')
resp.set_cookie('IDTOK', u.id_token)
resp.set_cookie('RTOK', u.refresh_token)
resp.headers["Access-Control-Allow-Credentials"]=True
resp.headers["Access-Control-Allow-Origin"]="*"
return resp
except ClientError as e:
print(username + ": ", e.response['Error']['Message'])
return make_err_resp(e.response['Error']['Message'], 400)
from flask_cors import CORS
CORS(app,origin='http://localhost:3000',credentials='true')
Assuming nothing is wrong with your code, I think it may be due to using localhost. Try mapping a hostname to localhost in your hosts file and using that instead: 127.0.0.1 testsite.dev and set the cookies for http://testsite.dev:port

Redux-Form v6.5.0 SubmissionError in onSubmit Function is Not Passing Along field errors / _error, giving "Uncaught (in promise)" Error in Console

So, along with Redux-Form I am using axios and thunk as middleware, and when I am in the onSubmit function (loginUser), and do AJAX calls with Axios. Unfortunately, when I want to signal that my user's submitted credentials are invalid and throw a SubmissionError to signal that the onSubmit function failed, and therefore get the errors displayed on the form I am getting "Uncaught (in promise)".
I have read from other threads that I might have to return a promise at some point, but I'm not entirely sure how to implement that (if that is even the problem).
Currently using version Redux-Form 6.5.0. Any help would be appreciated.
import axios from 'axios';
import { SubmissionError } from 'redux-form';
export function loginUser({ email, password }) {
return function(dispatch) {
axios.post(`${API_URL}/authenticate`, { email, password })
.then(response => {
console.log('status is: ', status, ' response is: ', response);
if(response.data.token){
cookie.save('token', response.data.token, { path: '/' });
dispatch({ type: AUTH_USER });
browserHistory.push('/');
} else {
if(response.data.success === false) {
var errObj = { email: "Invalid email and password combo", _error: "That email and password combination did not work. Please try again."};
throw (errObj)
}
}
})
.catch((error) => {
throw(new SubmissionError(error));
})
}
}
Error in console:
Uncaught (in promise) >
SubmissionError
errors
:
Object
message
:
"Submit Validation Failed"
name
:
"SubmissionError"
stack
:
"SubmissionError: Submit Validation Failed↵ at eval (eval at <anonymous> (http://localhost:8080/bundle.js:14:22671), <anonymous>:94:1297)"
__proto__
:
ExtendableError
For those of you wondering, I used 'resolve' and 'reject' with the SubmissionError inside of the reject() function as such (also notice the new Promise part at the top):
export function registerUser({ email, password }) {
return new Promise((resolve, reject) => {
axios.post('http://localhost:8088/api/users', { email: email, password: password })
.then(response => {
console.log('response is: ' , response, 'response.data is: ', response.data, 'response.code is: ', response.code);
if(response.data.success){
console.log('registerUser response.data.success is true')
cookie.save('token', response.data.token, { path: '/' });
store.dispatch({ type: AUTH_USER });
browserHistory.push('/');
resolve();
} else {
if(response.data.code === 11000){ //duplicate email
console.log('data code = 11000')
var errObj = new SubmissionError({_error: 'User registration failed, email already exists.' }) //need to add store dispatch for failed user registration (for form feedback)
reject(errObj);
} else if (response.code === 2) {
console.log('response.code = 2')
var errObj = new SubmissionError({ email: 'Invalid email pattern.' })
reject(errObj);
}
}
}).catch((error) => {
console.log('error is: ', error)
//errorHandler(store.dispatch, error, AUTH_ERROR)
if(error instanceof SubmissionError) reject(error);
});
})
}

Resources