Pass data from react component to proxy(node server) - node.js

I set up a proxy to bypass CORS for the intended api in this react application. I'm having trouble to pass data from react component to proxy(nodeJS server). I've read a few links such as here and here but still have no clues.
/*React component*/
import React, { useState } from "react";
import axios from "axios";
export default function Mail() {
const [emailInput, setEmailInput] = useState('')
const getMail = () => {
axios.get("/list/members").then(json => {
console.log(json.data);
});
};
const subscribe = (email) => {
console.log('inside subscribe')
axios.post("/member", email)
.then(data => console.log('post succeeds'))
.catch(err => console.log(err))
}
const handleSubmit = e => {
e.preventDefault();
const email = {
email_address: `${emailInput}`,
status: "subscribed"
};
subscribe(email)
};
const handleChange = (e) => {
setEmailInput(e.target.value)
}
return (
<form onSubmit={handleSubmit}>
<input type="text" name="email" placeholder="enter your email" value={emailInput} onChange={handleChange}/>
<input type="submit" value="subscribe" />{" "}
</form>
);
}
In node server, I have
app.post("/member", (req, res) => {
const email = {
email_address: "axios1234#gmail.com",
status: "subscribed"
};
axios.post(
"https://<apilink>",
email,
{
withCredentials: true,
auth: {
username: "anystring",
password: "<apikey>"
}
}
).then(json => {
res.send(json.data)
}).catch(err => {
console.log(err);
})
});
I've checked that my conduit between react front end app and proxy server is working. I also examined both req and res in app.post("/member", (req, res) but found thatreq.body is undefined and couldn't find the email object that was passed in from react function component. Did I miss anything here?

Are you using a body-parser? If not, install body-parser and then change your code to this:
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.post("/member", (req, res) => {
const email = req.body.email_address;
axios.post(
"https://<apilink>",
email,
{
withCredentials: true,
auth: {
username: "anystring",
password: "<apikey>"
}
}
).then(json => {
res.send(json.data)
}).catch(err => {
console.log(err);
})
});

Related

How to store a cookie sent from Express server by using fetch API in React?

I'm trying to create signup Form using React, Express and MongoDB. I succeffuly implemented the post request and saved the user data in the database.
However,though the user is saved in the database, I failed to store ( see it the browser ) the jwt token using res.cookie('jwt',token).
I have a simple form made in React:
type Props = {
children: React.ReactNode;
};
export const SignupLayout = ({ children }: Props) => {
const user = {
email: 'alexy#gmail.com',
username: 'alexladies',
password: 'pasrfsfsdfgfdsd',
securityQuestion: "father's name",
securityAnswer: 'jhon',
joinedDate: '12-12-2023',
};
const handleSignup = async (event: React.SyntheticEvent) => {
event.preventDefault();
// The problem is here
await fetch('http://localhost:3000/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(user),
})
.then((reponse) => reponse.json())
.then((json) => console.log(json))
.catch((err) => console.log(err));
};
return (
<form
onSubmit={handleSignup}
method='post'
action='/signup'
className='sm:px-20 md:w-2/3 md:px-12 lg:w-1/2 lg:px-4 lg:my-4 xl:mt-16 xl:w-1/3 xl:px-16 mx-auto bg-white rounded-2xl py-10 text-center '
>
{children}
</form>
);
};
My express server:
const User = require('../../models/user');
const { handleError } = require('./error');
const { createToken } = require('../utils/token');
const getSignup = (req, res) => {
// It stores the cookie in the browser succesfully
res.cookie('name', 'value');
res.send('ok');
};
const postSignup = async (req, res) => {
// It failed to store the cookie in the browser !
const {
email,
password,
username,
securityQuestion,
securityAnswer,
joinedDate,
} = req.body;
const user = new User({
email,
password,
username,
securityQuestion,
securityAnswer,
joinedDate,
});
await user
.save()
.then(() => res.cookie('jwt', createToken(user._id)))
.then(() => res.status(200).json(user._id))
.catch((err) => {
res.status(400).json(handleError(err));
});
};
module.exports = { getSignup, postSignup };
I have tried to add:
credentials:'include'
But it does not work.
Sreenshot

getting undefined of an array of errors

I am having an issue with my React Redux and Node app. I am trying to Log in an existing user but in my console i am getting the following error:
Uncaught (in promise) TypeError: error.response.data is undefined
The console points to the following block of code:
export const login = (email, password) => async (dispatch) => {
const body = { email, password };
try {
const res = await axios.post('http://localhost:5000/api/auth', body);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data
});
dispatch(loadUSer());
} catch (err) {
const errors = err.response.data.errors;
if (errors) {
errors.forEach((error) => dispatch(setAlert(error.msg, 'danger')));
}
dispatch({
type: LOGIN_FAIL
});
}
};
This is my server side for user auth auth.js:
const express = require('express');
const router = express.Router();
const User = require('../../models/User');
const auth = require('../../middleware/auth');
const config = require('config');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { check , validationResult } = require('express-validator/');
//#route GET api/auth
//#desc Test route
//#access public
router.get('/',auth, async(req, res)=> {
try{
const user = await User.findById(req.user.id).select('-password');
res.json(user);
}catch(err){
console.error(err.message);
res.status(500).send('Server Error');
}
});
//#route POST api/auth
//#desc Authenticate user & get token
//#access public
router.post('/', [
check('email', 'Plese include a valid email').isEmail(),
check('password', 'Password is required').exists()
],
async (req, res)=> {
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({ errors:errors.array()}); //400 is for bad requests
}
const { email, password } = req.body;
try{
//See if user exists
let user = await User.findOne({ email });
if(!user){
return res.status(400).json({ errors: [{ msg:'Invalid credentials' }] });
}
//Compare the input password, plane text, to the encrypted password.
const isMatch = await bcrypt.compare(password, user.password);
if(!isMatch){
return res.status(400).json({ errors: [{ msg:'Invalid credentials' }] });
}
//Return jsonwebtoken -> this for users to be logged in right after registration
const payload = {
user:{
id: user.id
}
}
jwt.sign(
payload,
config.get('jwtSecret'),
{expiresIn: 360000}, //change to 3600 for production
(err, token)=>{
if(err) throw err;
res.json({ token });
}
)
}catch(err){
console.error(err.message);
res.status(500).send('Server Error');
}
});
module.exports = router;
And this is my Login component:
import React, { Fragment, useState } from 'react'
/* import axios, { Axios } from 'axios'; */
import { Link, Navigate } from 'react-router-dom'
import { connect } from 'react-redux';
import { PropTypes } from 'prop-types';
import { login } from '../../actions/auth';
const Login = ({ login, isAuthenticated }) => {
const [formData, setFormData] = useState({
email: '',
password: ''
});
const { email, password } = formData;
const onChange = e => setFormData({
...formData, [e.target.name]:e.target.value
});
const onSubmit = async e => {
e.preventDefault();
login(email, password);
}
//Redirect if logged in
if(isAuthenticated){
return <Navigate to="/dashboard"/>;
}
return (
<Fragment>
<section className='container'>
<h1 className="large text-primary">Sign Up</h1>
<p className="lead"><i className="fas fa-user"></i> Sign Into Your Account</p>
<form className="form" action="create-profile.html" onSubmit={e => onSubmit(e)}>
<div className="form-group">
<input type="email"
placeholder="Email Address"
name="email" value={email}
onChange={e => onChange(e)}
required/>
</div>
<div className="form-group">
<input
type="password"
placeholder="Password"
name="password"
minLength="6"
value={password}
onChange={e => onChange(e)}
required
/>
</div>
<input type="submit" className="btn btn-primary" value="Login" />
</form>
<p className="my-1">
Don´t have an account? <Link to="/register">Sign up</Link>
</p>
</section>
</Fragment>
)
}
Login.propTypes = {
login: PropTypes.func.isRequired,
isAuthenticated: PropTypes.bool
}
const mappedStateToProps = state => ({
isAuthenticated: state.auth.isAuthenticated
})
export default connect(mappedStateToProps , { login })(Login)
For some reason there are sometimes i am able to login and sometimes i encounter this issue but i cannot figure out what am i doing wrong.
My redux devtools also show the AUTH_ERROR action type:
This is my auth.js in my actions directory.
export const loadUSer = () => async dispatch => {
if(localStorage.token){
setAuthToken(localStorage.token);
}
try {
const res = await axios.get('http://localhost:5000/api/auth');
dispatch({
type: USER_LOADED,
payload: res.data
})
} catch (error) {
dispatch({
type:AUTH_ERROR
})
}
}
auth.js (reducers directory):
import{
REGISTER_FAIL,
REGISTER_SUCCESS,
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT
} from '../actions/types'
const initialState = {
token: localStorage.getItem('token'),
isAuthenticated: null,
loading: true,
user: null
}
function authReducer(state = initialState, action){
const { type, payload } = action
switch (type) {
case USER_LOADED:
return {
...state,
isAuthenticated:true,
loading: false,
user:payload
}
case LOGIN_SUCCESS:
case REGISTER_SUCCESS:
localStorage.setItem('token', payload.token);
return {
...state,
...payload,
isAuthenticated: true,
loading: false
}
case LOGOUT:
case LOGIN_FAIL:
case REGISTER_FAIL:
case AUTH_ERROR:
localStorage.removeItem('token');
return {
...state,
toke: null,
isAuthenticated: false,
loading: false
}
default:
return state;
}
}
export default authReducer
So i first log in with an user everything works fine, i logout and log in with a different user and also works, i now logout and want to login to the first user again and the error shows up. The only difference between both users is that one has a profile and the other one doesn´t.
When i try to log in with the user with no profile my app crashes and my vscode terminal shows a different errors:
Can't set headers after they are sent to the client

how to retrieve jwt stored in cookies

I am exercising authentication for MERN stack and I decided to store JWT inside cookies, where during login new token will be sent to the cookies and during logout the function checks for the token from the request and clears the cookie and removes the token from database. I can send the cookie inside node with res.cookie on http://localhost:3000/ without errors and see the content from chrome application, but when I console.log the cookie with req.cookies from http://localhost:3000/main, it is undefined
backend
server.js
const express = require("express");
const app = express();
require("dotenv").config();
const cors = require("cors");
const cookieParser = require("cookie-parser");
const dbConnect = require("./dbConnect");
const authRoutes = require("./routes/auth");
const refreshTokenRoutes = require("./routes/refreshToken");
const port = process.env.PORT;
dbConnect(); //connect to mongoDb database
app.use(
cors({
// origin: "http://localhost:3000/main",
origin: ["http://localhost:3000", "http://localhost:3000/main"],
methods: "GET, POST, UPDATE, DELETE",
credentials: true,
})
);
app.use(express.json());
app.use(cookieParser());
app.use("/api", authRoutes);
app.use("/api/refreshToken", refreshTokenRoutes);
app.get("/", (req, res) => {
res.send("hello");
});
app.listen(port, () => {
console.log(`listening on http://localhost:${port}`);
});
auth.js
router.post("/login", async (req, res) => {
try {
//check if the input is in a valid format
const { error } = logInBodyValidation(req.body);
if (error) {
res.status(400).json({ error: true, message: error.details[0].message });
}
//check if the user is registered in the database
const user = await users.findOne({
email: req.body.email,
});
const passwordCheck = await bcrypt.compare(
req.body.password,
user.password
);
if (!user || !passwordCheck) {
res
.status(401)
.json({ error: true, message: "invalid email or password" });
}
const { accessToken, refreshToken } = await generateToken(user);
res
.cookie("jwtoken", refreshToken, {
maxAge: 1296000000,
path: "/",
domain: "localhost:3000",
httpOnly: true,
})
.status(200)
.json({
error: false,
accessToken,
refreshToken,
message: "Logged in sucessfully!",
});
} catch (error) {
// res.status(500).json({ error: true, message: "Internal Server Error" });
}
});
req.cookies returns the cookies
refreshToken.js
// logout
router.get("/", async (req, res) => {
try {
const { error } = refreshTokenBodyValidation(req.user);
if (error)
return res
.status(400)
.json({ error: true, message: error.details[0].message });
const userToken = await UserToken.findOne({
token: req.user.refreshToken,
});
if (!userToken)
return res
.status(200)
.json({ error: false, message: "Logged Out Sucessfully!" });
await userToken.remove();
res
.clearCookie("jwtoken")
.status(200)
.json({ error: false, message: "Logged Out Sucessfully!" });
} catch (error) {
console.log(error)
}
});
req.cookies returns [Object: null prototype] {}
Frontend
Login.js
import React from "react";
const Login = ({ email, password, setEmail, setPassword }) => {
const loginUser = async (e) => {
e.preventDefault();
try {
const response = await fetch("http://localhost:5000/api/login", {
headers: {
"Content-type": "application/json",
},
method: "POST",
credentials: "include",
body: JSON.stringify({
email,
password,
}),
});
const data = await response.json();
localStorage.setItem("token", data);
console.log(data);
// window.location.href = "/main";
} catch (error) {
console.log(error);
}
};
return (
<div className="container">
<h1>Login</h1>
<form onSubmit={loginUser}>
<input
title="Email"
// value={email}
placeholder="Enter E-mail"
type="email"
className="email"
onChange={(e) => {
setEmail(e.target.value);
}}
/>
<input
title="Password"
// value={password}
placeholder="Enter Password"
type="password"
className="pass"
onChange={(e) => {
setPassword(e.target.value);
}}
/>
<button>Log in</button>
</form>
</div>
);
};
export default Login;
Logout.js
import React from "react";
const Logout = () => {
const logoutUser = async () => {
const response = await fetch("http://localhost:5000/api/refeshToken/", {
headers: {
"Content-type": "application/json",
},
method: "GET",
});
const data = await response.json();
if (data.user) {
alert("Logged out successfuly");
window.location.href = "/";
}
};
return (
<div className="logout">
<button
className="logout_button"
title="Logout"
onClick={(e) => logoutUser(e)}
>
Log out
</button>
</div>
);
};
export default Logout;
the problem was a CORS error, must include credentials: "include" in the logout fetch request header

Can not retrive user from mongodb using findOne

I am making a simple Walk-In register app where i will register a customer and then find that specific customer by their phone number. The registration part is done but i cannot get a customer by their phone number. A little help will be very much appreciated. Below im posting both my backend and frontend code.
API-Server.js
const express = require('express');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const cors = require('cors')
const customerRouter = require('./routes/customer');
const app = express();
const port = process.env.PORT || 5000;
dotenv.config();
app.use(cors())
app.use(express.json());
app.use('/api/customer', customerRouter);
mongoose
.connect(process.env.MONGO_URI)
.then((data) => {
console.log(
'MongoDb connected successfully....'
);
})
.catch((err) => {
console.log(err);
});
app.listen(port, () => {
console.log(`Server is running at Port ${port}`);
});
API - customerRoute.js
const router = require('express').Router();
const Customer = require('../models/Customer');
router.post('/add', (req, res) => {
const newCustomer = new Customer({
name: req.body.name,
phone: req.body.phone,
address: req.body.address,
pin: req.body.pin,
});
newCustomer
.save()
.then((cx) => {
if (!cx) {
res
.status(400)
.send('Error creating a new customer');
} else {
res.send(cx);
}
})
.catch((err) => {
res.status(500).json({ err });
});
});
router.get('/', (req, res) => {
Customer.find()
.then((cx) => {
if (!cx) {
res
.status(400)
.send('Error getting customer');
} else {
res.send(cx);
}
})
.catch((err) => {
res.status(500).json({ err });
});
});
router.get('/getbyphone', (req, res) => {
Customer.findOne({ phone: req.body.phone })
.then((cx) => {
if (!cx) {
res
.status(400)
.send('Error getting customer');
} else {
res.send(cx);
}
})
.catch((err) => {
res.status(500).json({ err });
});
});
router.get('/getbyname', (req, res) => {
Customer.findOne({ name: req.body.name })
.then((cx) => {
if (!cx) {
res
.status(400)
.send('Error getting customer');
} else {
res.send(cx);
}
})
.catch((err) => {
res.status(500).json({ err });
});
});
module.exports = router;
Frontend - App.js
import { BrowserRouter as Router } from 'react-router-dom';
import { Route } from 'react-router-dom';
import Navbar from './components/Navbar';
import Search from './components/Search';
import Submit from './components/Submit';
function App() {
return (
<Router>
<div className='App'>
<Navbar />
<Route path='/' exact component={Submit} />
<Route path='/view' component={Search} />
</div>
</Router>
);
}
export default App;
frontend - search.js
import axios from 'axios';
import React, { Component } from 'react';
export default class Search extends Component {
constructor() {
super();
this.state = {
phone: '',
};
}
onPhoneChange = (event) => {
this.setState({
phone: event.target.value,
});
};
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.phone);
axios
.get(
'http://localhost:5000/api/customer/getbyphone',
this.state.phone
)
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
this.setState({
phone: '',
});
};
render() {
return (
<div>
<h3>Search for a Customer</h3>
<form
onSubmit={this.handleSubmit}
className='form-control form-control-sm'>
<div className='form-group'>
<label>Phone: </label>
<input
type='text'
required
className='form-control'
onChange={this.onPhoneChange}
value={this.state.phone}
/>
</div>
<div className='form-group'>
<input
type='submit'
className='btn btn-primary'
value='Search Customer'
/>
</div>
</form>
</div>
);
}
}
you could change this route and read phone number from params
router.get('/getbyphone/:phone', (req, res) => {
Customer.findOne({ phone: req.params.phone }) // change this line
.then((cx) => {
if (!cx) {
res
.status(400)
.send('Error getting customer');
} else {
res.send(cx);
}
})
.catch((err) => {
res.status(500).json({ err });
});
});
and change the react part like this
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.phone);
axios
.get(
'http://localhost:5000/api/customer/getbyphone'+this.state.phone /// change this line
)
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
this.setState({
phone: '',
});
};

why is my res.status showing nothing when I console log it?

I'm trying to check a login form with passport js and I want that when the status is correct, to log the user in but when it is incorrect to return him to the login page. I've tried doing this with an if else statement but it is not working as I've tried to console log the status and it shows nothing.
This is my frontend:
import React, {useState} from 'react'
import './login.css'
import axios from 'axios'
import { useHistory } from "react-router-dom";
function Login() {
const [username, setUsername] = useState("")
const [password, setPassword] = useState("")
const [data, setData] = useState(null)
const history = useHistory()
const onChangeUsername = (e) => {
setUsername(e.target.value)
}
const onChangePassword = (e) => {
setPassword(e.target.value)
}
const onSubmit = (e) => {
e.preventDefault()
const users = {
username: username,
password: password
}
axios.post('http://localhost:4000/users/login', users)
.then(res => console.log(res.data))
}
const loginUser = () => {
axios.get("http://localhost:4000/users/login", {
withCredentials: true
}).then(res => {
if(res.status === 200) {
setData(res)
return history.push("/home")
}
else if(res.status === 400) {
return history.push("/login")
}
console.log(res.status)
})
}
return (
<div>
<img src="https://www.freepnglogos.com/uploads/twitter-logo-png/twitter-logo-vector-png-clipart-1.png" className="twitterlogo____image"/>
<h1 className="login_____headertext">Log in to Twitter</h1>
<div className="placeholder_____global">
<form onSubmit={onSubmit}>
<input className="placeholder____div" placeholder="Phone, email or username" onChange={onChangeUsername}/>
<div>
<input className="placeholder____div" placeholder="Password" type="password" onChange={onChangePassword}/>
</div>
<div>
<button className="twitter___loginbuttonpage" onClick={loginUser}>Log in</button>
</div>
</form>
<div className="forgetPassword_____div">
<p>Forgot password?</p>
<p>·</p>
<p>Sign up for Twitter</p>
</div>
</div>
</div>
)
}
export default Login
Server side code:
const express = require('express');
const router = express.Router();
const Users = require('../models/users.model.js')
const passport = require("passport")
require('../authentication/passportConfig.js')(passport)
router.route('/').get((req, res) => {
Users.find()
.then(users => res.json(users))
.catch(err => res.status(400).json('Error:' + err))
})
router.route('/login').post((req, res, next) => {
passport.authenticate("local" , (err, user, info) => {
if (err) throw err;
if (!user) res.status(400).send("No user exists");
else {
req.logIn(user, err => {
if (err) throw error;
res.status(200).send("Succesfully Authenticated")
})
}
})(req, res, next)
})
router.route('/login').get((req, res) => {
res.send(req.user)
})
router.route('/add').post(async(req,res) => {
const hashedPassword = await bcrypt.hash(req.body.password, 10)
const username = req.body.username
const password = hashedPassword
const email = req.body.email
const phone = req.body.phone
const monthOfBirth = req.body.monthOfBirth
const dayOfBirth = req.body.dayOfBirth
const yearOfBirth = req.body.yearOfBirth
const newUsers = new Users({
username,
password,
email,
phone,
monthOfBirth,
dayOfBirth,
yearOfBirth
})
newUsers.save()
.then (() => res.json("User Added"))
.catch(err => res.status(400).json('error' + err))
})
module.exports = router
Before reaching console you are returning the control in if else conditions.
move your console.log before if else.
const loginUser = () => {
axios.get("http://localhost:4000/users/login", {
withCredentials: true
}).then(res => {
console.log(res.status)
if(res.status === 200) {
setData(res)
return history.push("/home")
}
else if(res.status === 400) {
return history.push("/login")
}
})
}

Resources