I have written an API in Nodejs which helps in reset password using Mysql database.It is working fine in Postman.I have called this API in Expo IOS App.But I am getting Network request failed error. Below is the Node js program:
app.js:
var express = require('express');
var path = require('path');
var connection = require('./database.js');
var nodemailer = require('nodemailer');
const bcrypt = require("bcryptjs")
var randtoken = require('rand-token');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var flash = require('express-flash');
var session = require('express-session');
var bodyParser = require('body-parser');
const createError = require('http-errors');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
var connection = require('./database.js');
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: false}))
//send email
function sendEmail(email, token) {
var email = email;
var token = token;
var mail = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'c***********#gmail.com', // Your email id
pass: '**********' // Your password
}
});
var mailOptions = {
from: 'poornima#abccompany.com',
to: email,
subject: 'Reset Password Link - ABCCompany.com',
html: '<p>You requested for reset password, kindly use this link to reset
your password</p>'
};
mail.sendMail(mailOptions, function(error, info) {
if (error) {
console.log(1)
} else {
console.log(0)
}
});
}
app.post('/reset-password-email', function(req, res, next) {
var email = req.body.email;
console.log('email from api '+email);
connection.query('SELECT * FROM JTGDB.UserInfo WHERE email ="' + email + '"',
function(err, result) {
if (err) throw err;
var type = ''
var msg = ''
console.log(result[0]);
if (result[0].Email.length > 0) {
var token = randtoken.generate(20);
var sent = sendEmail(email, token);
if (sent != '0') {
var data = {
token: token
}
connection.query('UPDATE JTGDB.UserInfo SET ? WHERE email ="' + email + '"', data,
function(err, result) {
if(err) throw err
})
type = 'success';
msg = 'The reset password link has been sent to your email address';
} else {
type = 'error';
msg = 'Something goes to wrong. Please try again';
}
} else {
console.log('2');
type = 'error';
msg = 'The Email is not registered with us';
}
res.redirect('/');
});
})
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret: '123458cat',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}))
app.use(flash());
app.use('/', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.listen(4000, function () {
console.log('Node app is running on port 4000');
});
module.exports = app;
Below is the IOS App ForgetPassword Screen page:
ForgetPasswordScreen.js:
import React, { Component, Fragment, useState } from "react";
import { View, Text,SafeAreaView, Image, StyleSheet } from "react-native";
import { Formik } from "formik";
import * as Yup from "yup";
import FormInput from "../../components/UI/FormInput";
import FormButton from "../../components/UI/FormButton";
import ErrorMessage from "../../components/UI/ErrorMessage";
import * as authActions from '../../store/actions/auth';
import {useDispatch} from "react-redux";
import Toast from 'react-native-root-toast';
const validationSchema = Yup.object().shape({
email: Yup.string()
.label("Email")
.email("Enter a valid email")
.required("Please enter a registered email"),
});
const ForgotPasswordScreen = props => {
const [isLoading,setIsLoading] = React.useState(false);
const [error, setError] = React.useState('');
const dispatch = useDispatch();
const handlePasswordReset = async (values, actions) => {
const { email } = values;
console.log('email is '+email);
let action
action = authActions.resetpassword(
email
);
setError(null);
setIsLoading(true);
try{
await dispatch(action);
props.navigation.navigate("Login");
} catch (error) {
actions.setFieldError("general", error.message);
}
};
return (
<SafeAreaView>
<View style={styles.emailiconview}>
<Image source={require('../../assets/reset_email.png')} />
</View>
<View style ={styles.instrview1}>
<Text>
Please enter your registered email address below to
</Text>
</View>
<View style={styles.instrview2}>
<Text>receive password reset instruction</Text>
</View>
<View style={styles.emailinputview}>
<Formik
initialValues={{ email: "" }}
onSubmit={(values, actions) => {
handlePasswordReset(values, actions);
}}
validationSchema={validationSchema}
>
{({
handleChange,
values,
handleSubmit,
errors,
isValid,
touched,
handleBlur,
isSubmitting,
}) => (
<Fragment>
<FormInput
name="email"
value={values.email}
onChangeText={handleChange("email")}
placeholder="Enter email"
autoCapitalize="none"
iconName="ios-mail"
iconColor="blue"
onBlur={handleBlur("email")}
/>
<ErrorMessage errorValue={touched.email && errors.email} />
<View style={styles.buttonContainer}>
<FormButton
buttonType="outline"
onPress={handleSubmit}
title="Send Email"
buttonColor="blue"
disabled={!isValid || isSubmitting}
/>
</View>
<ErrorMessage errorValue={errors.general} />
</Fragment>
)}
</Formik>
</View>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
marginTop: 150,
},
text: {
color: "#333",
fontSize: 24,
marginLeft: 25,
},
buttonContainer: {
margin: 25,
},
emailiconview:{
justifyContent:'center',
alignItems:'center',
top:"30%"
},
instrview1:{
top:'40%',
justifyContent:'center',
alignSelf:'center'
}, instrview2:{
top:'45%',
justifyContent:'center',
alignSelf:'center'
},
emailinputview:{
top:'50%'
}
});
export default ForgotPasswordScreen;
Below is the store auth where I fetch API:
auth.js:
import Device from '../../model/Device';
import AsyncStorage from '#react-native-async-storage/async-storage'
export const FORGOTPASSWORD = 'FORGOTPASSWORD';
export const resetpassword=(email) =>{
console.log(email);
return async dispatch =>{
const response = await fetch(
'http://my_IPV4_Address:4000/reset-password-email',
{
method: 'POST',
header: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email
})
}
);
const resData = await response.text();
console.log(resData);
dispatch({type:FORGOTPASSWORD});
};
}
After running this I am getting the below error in Expo:
Network request failed
It is taking email, but not hitting the api.
email is cpoornima.1987#gmail.com
Email id to API cpoornima.1987#gmail.com
I am getting below error in NodeJs:
email from api undefined
undefined
I have added
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
to the Info.plist. I am just checking in IOS Simulator attached to Expo App. How to get through this?
Below is the auth.js fetch API which is working good.As soon as I press Send Email button, an email is going to provided email id for reset password using real Iphone device.
auth.js:
import Device from '../../model/Device';
import AsyncStorage from '#react-native-async-storage/async-storage'
export const FORGOTPASSWORD = 'FORGOTPASSWORD';
export const resetpassword=(email) =>{
const formData = new FormData();
formData.append('email',email);
console.log('Email id to API '+email);
return async dispatch =>{
fetch('http://My_IPV4_Address:4000/reset-password-email',
{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body:JSON.stringify({
email: email,
}),
})
.then(res => res.text())
.then(
(signupresult) =>{
}).catch(err =>{
console.log(err);
})
dispatch({type:FORGOTPASSWORD});
};
}
Related
I am trying to add a contact form that will send to a dedicated gmail account. I have got the contact form working independently but when I try and add it to my working project it does not work and the error I get is:
Cannot POST /api/send
The project is a MERN stack. Below is the mailer.js middleware:
import nodemailer from 'nodemailer'
import config from '../config'
const transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
port: 587,
auth: {
user: process.env.username,
pass: process.env.password,
}
});
const send = ({ email, name, text }) => {
const from = name && email ? `${name} <${email}>` : `${name || email}`
const message = {
from,
to: 'react.nodemailer#gmail.com',
subject: `New message from ${from} at creating-contact-forms-with-nodemailer-and-react`,
text,
replyTo: from
};
return new Promise((resolve, reject) => {
transporter.sendMail(message, (error, info) =>
error ? reject(error) : resolve(info)
)
})
}
export default send
The server.js on the backend is:
const express = require('express');
const connectDB = require('./config/db');
const path = require('path');
// // ********************
// // CONTACT FORM
// // ********************
const cors = require ("cors")
const nodemailer = require("nodemailer")
// // ********************
// // CONTACT FORM
// // ********************
const app = express();
// // Connect Database
connectDB();
// Init Middleware
app.use(express.json());
// // ********************
// // CONTACT FORM
// // ********************
app.use(cors());
app.post('/contact', (req, res) => {
const { email = '', name = '', message = '' } = req.body
mailer({ email, name, text: message }).then(() => {
console.log(`Sent the message "${message}" from <${name}> ${email}.`);
res.redirect('/#success');
}).catch((error) => {
console.log(`Failed to send the message "${message}" from <${name}> ${email} with the error ${error && error.message}`);
res.redirect('/#error');
})
})
// // ********************
// // CONTACT FORM
// // ********************
// Define Routes
app.use('/api/users', require('./routes/api/users'));
app.use('/api/auth', require('./routes/api/auth'));
app.use('/api/profile', require('./routes/api/profile'));
app.use('/api/posts', require('./routes/api/posts'));
app.use('/api/send', require('./routes/api/send'));
// Serve static assets in production
if (process.env.NODE_ENV === 'production') {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
The contact form is:
import React, { Component } from "react";
import axios from "axios";
class ContactForm extends Component {
constructor() {
super();
this.state = {
name: "",
email: "",
message: "",
status: "Submit"
};
}
handleSubmit(event) {
event.preventDefault();
this.setState({ status: "Sending" });
axios({
method: "POST",
url: "api/send",
data: this.state,
}).then((response) => {
if (response.data.status === "sent") {
alert("Message Sent");
this.setState({ name: "", email: "", message: "", status: "Submit" });
} else if (response.data.status === "failed") {
alert("Message Failed");
}
});
}
handleChange(event) {
const field = event.target.id;
if (field === "name") {
this.setState({ name: event.target.value });
} else if (field === "email") {
this.setState({ email: event.target.value });
} else if (field === "message") {
this.setState({ message: event.target.value });
}
}
This is the api POST route.
var express = require('express');
var config = require('config');
var router = express.Router();
var cors = require('cors');
// #route POST api/send
// #desc Send email on contact page
// #access Public
router.post('/api/send',(req, res, next ) => {
var name = req.body.name
var email = req.body.email
var subject = req.body.subject
var message = req.body.message
var content = `
name: ${name} \n
email: ${email} \n
subject: ${subject} \n
message: ${message} `
var post = {
from: name,
subject: subject,
text: content
}
});
module.exports = router;
I have been trying to debug this for a week or so. I am currently trying to find out why the POST route is not working.
The error codes I have got are 500 internal server error and 404 not found. The url it will be going to is http://localhost:5000/api/send
Change
router.post('/api/send',(req, res, next )
to
router.post('/',(req, res, next )
In your express app your already have.
app.use('/api/send', require('./routes/api/send'));
Thus, for all "/api/send" we will look in the file './routes/api/send'.
The way you defined it you will have to query it like http://localhost:5000/api/send/api/send.
You will have
router.post('/',(req, res, next ) => {
var name = req.body.name
var email = req.body.email
var subject = req.body.subject
var message = req.body.message
var content = `
name: ${name} \n
email: ${email} \n
subject: ${subject} \n
message: ${message} `
var post = {
from: name,
subject: subject,
text: content
}
});
module.exports = router;
Also how about moving routes to its own file. i.e in server have
app.use(require('./routes/api'));
And in ./routes/api/index.js have the definitions there. i.e
const express = require('express');
const router = express.Router();
router.use('/api/send', require('./send'));
module.exports = router;
You can directly register the route on the express app like below,
app.post('/api/send',function(){
//..send code
//nodemailer.send("blabla")
});
instead of registering routes both on app and router.
I am trying to set a cookie in the browser for authentication. When using POSTMAN the cookie is returned with no problem, as well as any other response I send. However in the react app, it is failing to fetch. It seems to be complaining about CORS, in particular this line of code being set to : res.header("Access-Control-Allow-Origin", "");
I have an app.js file in which I configure CORS and all of my routes, and my basic fetches work perfectly. When attempting to set a cookie in a route file, it fails to fetch. Here is the app.js file
//packages
var bodyParser = require ('body-parser')
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors = require('cors');
var mysql = require('mysql');
//routes
const accountRouter = require('./routes/account');
//express app
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(cors());
app.use(bodyParser.json());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
//use routes
app.use('/account', accountRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// Tells Express to allows data to be sent across different origins
// required by CORS policy
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "localhost:3001");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
Here is my route file that checks for an existing email, then verifies the password. After verifying the password I generate the token, and send it as a cookie. Again, in POSTMAN this functions fine.
var express = require('express');
var router = express.Router();
var bcryptjs = require('bcryptjs')
var cookieParser = require('cookie-parser');
var jwt = require('jsonwebtoken');
var pool = require('../database/accountsdb');
const saltRounds = 12;
function authenticate(req,res) {
//Check for existing email
//Create DB Connection
pool.getConnection(function(err, connection){
if(err) {
connection.release();
res.json({"code": 100, "status": "Error in database connection"});
return;
}
//Variables and SQL
let emailSQL ='SELECT intAccountID FROM accountdetails where strEmail = ?';
let email = req.body.email;
connection.query(emailSQL, email, function(err, result){
if(!err){
//check if matching row was found
if(result.length>0){
//Get password
let accountID = result[0].intAccountID;
let accountSQL = "SELECT strPassword, intAccountID FROM accounts WHERE intAccountID = ?";
connection.query(accountSQL, accountID, function(err, result){
if(!err){
//get password
let hashed = result[0].strPassword;
//get ID
let ID = result[0].intAccountID;
//compare passwords
bcryptjs.compare(req.body.password, hashed, function(err, result){
if(!err){
if(result== true){
let payload = {
check: true,
ID: ID
};
//generate token
let token = jwt.sign(payload, process.env.TOKEN_SECRET, {
expiresIn: 1440 //24 hours
});
//TESTING EXPIRE
//TESTING EXPIRE
let expiration= 1000;
//return token cookie
//NEED TO SEND COOKIE !!!!!!!!!!!!!!!!!!!!!
res.cookie('token', token, {
expires: new Date(Date.now() + expiration),
httpOnly: true,
});
}else{
//return failed
res.json({
message: 'Invalid Email or Password'
});
}
}else{
res.json({err: err});
}
})
}else{
//return error
res.json({err:err});
}
})
}else{
//return failed
res.json({
message: 'Invalid Email or Password'
});
}
}else{
connection.release();
res.json({err});
return;
}
connection.release();
})
connection.on('error', function(err){
res.json({"code": 100, "status": "Error in database connection"});
})
})
};
router.post('/authenticate', function(req, res){
authenticate(req, res);
});
module.exports = router;
Here is the react component to validate that a valid email was entered, the password is not empty, and the the API call to POST the data to express for authentication.
// Dependencies
import React, {Component} from 'react';
import validator from 'validator';
class Login extends Component{
constructor(props){
super(props);
this.state = {
email: '',
password:''
}
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChangeEmail = (event) => {
this.setState({email: event.target.value});
}
handleChangePass = (event) => {
this.setState({password: event.target.value});
}
verifyInput(data){
//Validate Email
if(validator.isEmail(data.email) == false){
return false;
}
}
handleSubmit(event){
let data = {
email: this.state.email,
password: this.state.password
}
let isValid= this.verifyInput(data)
if(isValid == false){
alert("Please enter a valid email address")
event.preventDefault();
}else{
//api parameters to register user
const url ='http://localhost:3001/account/authenticate'
const options = {
method:'POST',
headers:{
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8'
},
body: JSON.stringify(data)
}
//call api
fetch(url, options)
.then(response=> {
console.log(response.headers)
}).catch(error=>console.log(error))
}
}
render (){
return(
<div className="register">
<form onSubmit={this.handleSubmit}>
<table>
<tbody>
<tr>
<td>Email:</td>
<td>
<input type="email" value={this.state.email} onChange={this.handleChangeEmail} />
</td>
</tr>
<tr>
<td>Password:</td>
<td>
<input type="text" value={this.state.password} onChange={this.handleChangePass}></input>
</td>
</tr>
<tr>
<td>
<input disabled={false} type="submit" value="Submit" onSubmit={(e) => this.handleSubmit(e)}/>
</td>
</tr>
</tbody>
</table>
</form>
</div>
)
}
}
export default Login;
What do I do in order to fix this issue? The react client is on localhost:3000 and express on localhost:3001
Try installing http-proxy-middleware using npm or Yarn, then create src/setupProxy.js and place the following contents in it:
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
proxy({
target: 'http://localhost:3001',
changeOrigin: true,
})
);
};
My app was working fine and I was able to fetch data between my Express and React servers. I reorganised my code and now i cannot get rid of the CORS errors and cannot fetch any data at all. I cannot move on with my project and simply can't figure it out for myself, I have really tried.
The front end works ok until i try to login, and then the authentication fails
I have tried adding headers and have installed CORS to my express app. I have a proxy specified in my react package.json to the express URL.
This is my Express server.js
const express = require('express');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const path = require('path');
const cors = require('cors');
const methodOverride = require('method-override');
const db = require('./db/index.js')
db.on('error', console.error.bind(console, 'MongoDB connection error:'))
require('dotenv').config();
const app = express();
app.disable('x-powered-by');
app.use(function(req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
app.use(methodOverride('_method'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(cors({
origin: 'http://localhost:8080'
}));
app.use(express.static(path.join(__dirname, '../build')));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, '../build', 'index.html'));
});
const userRouter = require('./routes/user-routes')
app.use('/api', userRouter)
const fileRouter = require('./routes/file-routes')
app.use('/file', fileRouter)
// mongoose.connection.once('open', run);
app.listen(process.env.PORT || 8080);
console.log('Server is listening on port ' + process.env.PORT);
This is my user controller
const User = require('../models/Users');
const secretShh = 'mysecretsshhh';
const jwt = require('jsonwebtoken');
const home = (req, res) => {
res.send('Welcome!');
};
const secret = (req, res) => {
res.send('The password is potato');
};
const register = (req, res) => {
const { email, password } = req.body;
const user = new User({ email, password });
user.save(function(err) {
if (err) {
console.log(err);
res.status(500).send("Error registering new user please try again.");
} else {
res.status(200).send("Welcome to the club!");
}
});
};
const authenticate = (req, res) => {
const { email, password } = req.body;
User.findOne({ email }, function(err, user) {
if (err) {
console.error(err);
res.status(500)
.json({
error: 'Internal error please try again'
});
} else if (!user) {
res.status(401)
.json({
error: 'Incorrect email or password'
});
} else {
user.isCorrectPassword(password, function(err, same) {
if (err) {
res.status(500)
.json({
error: 'Internal error please try again'
});
} else if (!same) {
res.status(401)
.json({
error: 'Incorrect email or password'
});
} else {
// Issue token
const payload = { email };
const token = jwt.sign(payload, secretShh, {
expiresIn: '1h'
});
res.cookie('token', token, { httpOnly: true }).sendStatus(200);
}
});
}
});
};
const token = (req, res) => {
res.sendStatus(200);
};
module.exports = {
home,
secret,
register,
authenticate,
token
}
this is my user routes
const express = require('express')
const UserCtrl = require('../controllers/user-ctrl')
const withAuth = require('../middleware');
const router = express.Router()
router.get('/home', UserCtrl.home)
router.get('/secret', withAuth, UserCtrl.secret)
router.post('/register', UserCtrl.register)
router.post('/authenticate', UserCtrl.authenticate)
router.get('/checktoken', withAuth, UserCtrl.token)
module.exports = router
this is a middleware function to check tokens, this is where the error seems to point towards, but I'm sure its actually something to do with the proxy and fetch being blocked by CORS.
const jwt = require('jsonwebtoken');
const secret = 'mysecretsshhh';
const withAuth = (req, res, next) => {
const token =
req.body.token ||
req.query.token ||
req.headers['x-access-token'] ||
req.cookies.token;
if (!token) {
res.status(401).send('Unauthorized: No token provided');
} else {
jwt.verify(token, secret, function(err, decoded) {
if (err) {
res.status(401).send('Unauthorized: Invalid token');
} else {
req.email = decoded.email;
next();
}
});
}
}
module.exports = withAuth;
this is my auth components where the error is also pointing towards
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
//withAuth is a high-order component which takes in a component to protect
export default function withAuth(ComponentToProtect) {
return class extends Component {
constructor() {
super();
this.state = {
loading: true,
redirect: false,
};
}
async componentDidMount() {
fetch('http://localhost:8080/api/checktoken', {
credentials: 'include',
mode: 'cors'
})
.then(res => {
if (res.status === 200) {
this.setState({ loading: false });
} else {
const error = new Error(res.error);
throw error;
}
})
.catch(err => {
console.error(err);
this.setState({ loading: false, redirect: true });
});
}
render() {
const { loading, redirect } = this.state;
if (loading) {
return null;
}
if (redirect) {
return <Redirect to="/login" />;
}
return (
<React.Fragment>
<ComponentToProtect {...this.props} />
</React.Fragment>
);
}
}
}
login component
import React, { Component } from 'react';
export default class Login extends Component { //impplicit vs explicit returns
constructor(props) {
super(props)
this.state = {
email : '',
password: ''
};
}
handleInputChange = (event) => {
const { value, name } = event.target;
this.setState({
[name]: value
});
}
onSubmit = async (event) => {
event.preventDefault();
fetch('/api/authenticate', {
method: 'POST',
body: JSON.stringify(this.state),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
if (res.status === 200) {
this.props.history.push('/');
} else {
const error = new Error(res.error);
throw error;
}
})
.catch(err => {
console.error(err);
alert('Error logging in please try again');
});
}
render() {
return (
<form onSubmit={this.onSubmit}>
<h1>Login Below!</h1>
<input
type="email"
name="email"
placeholder="Enter email"
value={this.state.username}
onChange={this.handleInputChange}
required
/>
<input
type="password"
name="password"
placeholder="Enter password"
value={this.state.password}
onChange={this.handleInputChange}
required
/>
<input type="submit" value="Submit"/>
</form>
);
}
}
This is the main error:
Access to fetch at 'http://localhost:8080/api/checktoken' from origin 'http://localhost:3000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8080' that is not equal to the supplied origin. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
It also says:
withAuth.jsx:17 GET http://localhost:8080/api/checktoken net::ERR_ABORTED 401 (Unauthorized)
In my express app the terminal says it cant read the token in the middleware, I presume its also due to cors :
TypeError: Cannot read property 'token' of undefined
at withAuth (/Users/nancycollins/virtuload-beta/backend/middleware.js:6:16)
Apologies if this is too much information I've just been stuck on this for too long and really dont know what else to do.
Update:
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
With:
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
I encourage you to do app.use(cors()); before those lines
app.disable('x-powered-by');
app.use(function(req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
...
Express stacks those functions lets say as a "array" and because of that the order matters
Hope it resolve your problem.
Bit late to the party but just going to leave my answer here incase someone else has the same problem.
The idea is to allow CORS request to your Express server. Go to the directory with your server.js file and run:
npm install cors
Then inside server.js add the following lines:
const cors = require('cors');
app.use(cors());
I am trying to retrieve my jwt token after login within my Profile component and store the token as within localstorage. I know that localstorage isnt the best option but this will be a native mobile app so localstorage from what I know is my best option. However when I sign in , I receive a token , here is an token that Ive received recently
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaGVjayI6dHJ1ZSwiaWF0IjoxNTYzMDUzMzk4LCJleHAiOjE1NjMwNTQ4Mzh9.tw8ks-jFZID5rmwhoNTkWV8598niE3zMFIDk4Gz-sVg
when my Profile component trys to retrieve /current it use jwt malformed
Server.js
var express = require('express');
var cors = require('cors');
var bodyParser = require('body-parser');
var app = express();
var port = process.env.PORT || 5000;
var morgan = require('morgan');
const auth = require('./middleware/auth');
const User = require('./models/User');
app.use(cors());
app.use(
bodyParser.urlencoded({
extended: false
})
);
app.use(bodyParser.json());
/*========= Here we want to let the server know that we should expect and allow a header with the content-type of 'Authorization' ============*/
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Headers', 'Content-type,Authorization');
next();
});
// use morgan to log requests to the console
app.use(morgan('dev'));
var Users = require('./routes/Users');
app.use('/users', Users);
// Create a Server
const PORT = process.env.PORT || 5000; // Environment variable or port 5000
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
module.exports = app;
User.js
const express = require('express');
const users = express.Router();
const cors = require('cors');
const jwt = require('jsonwebtoken');
var exjwt = require('express-jwt');
var jwtauth = require('../middleware/authjwt.js');
const bcrypt = require('bcrypt');
const bodyParser = require('body-parser');
const User = require('../models/User');
const config = require('config');
const auth = require('../middleware/auth');
const secret = 'dasdsad';
users.use(
bodyParser.urlencoded({
extended: true
})
);
users.use(bodyParser.json());
users.use(cors());
users.post('/register', (req, res) => {
const today = new Date();
const userData = {
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: req.body.password,
created: today
};
User.findOne({
where: {
email: req.body.email
}
})
//TODO bcrypt
//Need validation to appear on console and in view
.then(user => {
if (!user) {
bcrypt.hash(req.body.password, 10, (err, hash) => {
userData.password = hash;
User.create(userData)
.then(user => {
res.json({ status: user.email + 'Registered!' });
})
.catch(err => {
res.send('error: ' + err);
});
});
} else {
res.json({ error: 'User already exists' });
}
})
.catch(err => {
res.send('error: ' + err);
});
});
users.post('/authenticate', (req, res) => {
User.findOne({
where: {
email: req.body.email
}
}).then(user => {
if (user) {
if (bcrypt.compareSync(req.body.password, user.password)) {
const payload = {
check: true
};
const token = jwt.sign(payload, config.get('myprivatekey'), {
expiresIn: 1440 // expires in 24 hours
});
res.json({
message: 'authentication done ',
token: token
});
console.log('Successful Login');
console.log(user.first_name);
} else {
res.json({ message: 'please check your password !' });
console.log('incorrect password');
}
} else {
res.json({ message: 'user not found !' });
console.log('user cannot be found');
}
});
});
//users.get('/something', [express.bodyParser(), jwtauth], function(req, res) {
// do something
//});
// app.all('/api/*', [express.bodyParser(), jwtauth]);
users.get(
'/current',
exjwt({ secret: config.get('myprivatekey') }),
async (req, res) => {
const user = await User.findById(req.user._id).select('-password');
console.log(user);
res.send(user);
}
);
Login
import React, { Component } from 'react';
class Login extends Component {
constructor() {
super();
this.state = {
email: '',
password: '',
errors: {}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
onSubmit(e) {
e.preventDefault();
const user = {
email: this.state.email,
password: this.state.password
};
var token = window.localStorage.getItem('token');
fetch('http://localhost:5000/users/authenticate', {
method: 'POST', // or 'PUT'
body: JSON.stringify(user), // data can be `string` or {object}!
headers: {
'Content-Type': 'application/json'
}
});
}
render() {
return (
<div className='container'>
<div className='row'>
<div className='col-md-6 mt-5 mx-auto'>
<form noValidate onSubmit={this.onSubmit}>
<h1 className='h3 mb-3 font-weight-normal'>Please sign in</h1>
<div className='form-group'>
<label htmlFor='email'>Email address</label>
<input
type='email'
className='form-control'
name='email'
placeholder='Enter email'
value={this.state.email}
onChange={this.onChange}
/>
</div>
<div className='form-group'>
<label htmlFor='password'>Password</label>
<input
type='password'
className='form-control'
name='password'
placeholder='Password'
value={this.state.password}
onChange={this.onChange}
/>
</div>
<button
type='submit'
className='btn btn-lg btn-primary btn-block'
>
Sign in
</button>
</form>
</div>
</div>
</div>
);
}
}
export default Login;
This is how I am currently fetching the token within My Profile component
componentDidMount() {
var token = localStorage.getItem('token');
fetch('http://localhost:5000/users/current', {
//cahng taht
method: 'GET',
mode: 'cors',
headers: { Authorization: 'Bearer ' + token }
});
}
I guess the problem is on the expiresIn. 'expiresIn' expressed in seconds or a string describing a time span. You set 1440, which means 1440/60 = 24minutes => expires after 24 minutes not after 24 hours... Could you please try to set as below:
const token = jwt.sign(payload, config.get('myprivatekey'), {
expiresIn: '24h' // expires in 24 hours
});
I am trying to configure a node/express and react app with nodemailer and I can't seem to be getting emails sent. All the data is being sent to the node backend perfectly, however I can't seem to get an email sending through nodemailer. There is no error message on the console and I am not gettting any feedback from the smpt.transporter function on the console log. I was wondering if someone could help me out here? Much appreciated!
App.js
import React, { Component } from "react";
import PageOne from "./components/PageOne";
import PageTwo from "./components/PageTwo";
import PageThree from "./components/PageThree";
import PageFour from "./components/PageFour";
import PageFive from "./components/PageFive";
import PageSix from "./components/PageSix";
import { Button } from "semantic-ui-react";
import "semantic-ui-css/semantic.min.css";
import axios from "axios";
class App extends Component {
constructor(props) {
super(props);
this.state = {
generalDetails: "Text",
fName: "Text",
mName: "Text",
LName: "Text",
gender: "Text",
};
this.onContentChange = this.onContentChange.bind(this);
this.onSubmitForm = this.onSubmitForm.bind(this);
}
render() {
return (
<div className="App">
<PageOne handleChange={this.onContentChange} />
<PageTwo handleChange={this.onContentChange} />
<PageThree handleChange={this.onContentChange} />
<PageFour handleChange={this.onContentChange} />
<PageFive handleChange={this.onContentChange} />
<PageSix handleChange={this.onContentChange} />
<Button onClick={this.onSubmitForm}>Submit Form</Button>
<br />
<br />
</div>
);
}
onSubmitForm = e => {
e.preventDefault();
var data = {
generalDetails: this.state.generalDetails,
fName: this.state.fName,
mName: this.state.mName,
lName: this.state.lName,
};
axios
.post("http://localhost:5000/home", data)
.then(result => {
console.log(result)
})
.catch(() => {
console.log("Something went wrong. Please try again later");
});
};
//end
onContentChange(fieldname, data) {
console.log("On Content Change", data);
this.setState({
[fieldname]: data
});
}
}
export default App;
Server.js
const nodemailer = require('nodemailer')
const path = require('path')
const express = require('express')
const app = express()
const port = 5000
const cors = require('cors')
app.use(cors())
const bodyParser = require('body-parser')
app.use(bodyParser.json())
// to support JSON-encoded bodies
app.use(
bodyParser.urlencoded({
// to support URL-encoded bodies
extended: true
})
)
app.get('/home', (req, res) => {
console.log(
'Hello from .get /home',
req.body.generalDetails,
req.body.firstName,
req.body.mName
)
})
const http = require('http');
app.post('/home', (req, res) => {
var server = http.createServer(app)
server.listen(3000, function () {
console.log('Express is running on port 3000')
})
app.post('/home', function (req, res) {
var data=req.body;
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "email",
pass: "pass"
}});
smtpTransport.sendMail({ //email options
from: "email",
to: "email", // receiver
subject: "Emailing with nodemailer", // subject
text:req.body.generalDetails,
html: "here your data goes"// body (var data which we've declared)
}, function(error, response){ //callback
if(error){
console.log(error);
}else{
console.log("Message sent: " + res.message);
}
smtpTransport.close();
}); });
let data = [{
//page one data
generalDetails: req.body.generalDetails,
fName: req.body.fName,
mName: req.body.mName,
lName: req.body.lName,
email: req.body.email,
}];
res.json(data);
}
);
app.listen(port, () => `Server running on port ${port}`);
Since youa using Gmail make sure set the Access for less secure apps setting to Enable
Go to : https://www.google.com/settings/security/lesssecureapps to do it. In your code there seemes to be two routes with same name /home (both post endpoints). Why are you listening to server twice?. try this code.
const nodemailer = require('nodemailer')
const path = require('path')
const express = require('express')
const app = express()
const http = require('http');
const server = http.createServer(app)
const port = 5000
const cors = require('cors')
app.use(cors())
const bodyParser = require('body-parser')
app.use(bodyParser.json())
// to support JSON-encoded bodies
app.use(
bodyParser.urlencoded({
// to support URL-encoded bodies
extended: true
})
)
app.get('/home', (req, res) => {
console.log(
'Hello from .get /home',
req.body.generalDetails,
req.body.firstName,
req.body.mName
)
})
app.post('/home', function (req, res) {
var data=req.body;
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "email",
pass: "pass"
}});
smtpTransport.sendMail({ //email options
from: "email",
to: "email", // receiver
subject: "Emailing with nodemailer", // subject
text:req.body.generalDetails,
html: "here your data goes"// body (var data which we've declared)
}, function(error, response){ //callback
if(error){
console.log(error);
}else{
console.log("Message sent: " + res.message);
}
smtpTransport.close();
}); });
let data = [{
//page one data
generalDetails: req.body.generalDetails,
fName: req.body.fName,
mName: req.body.mName,
lName: req.body.lName,
email: req.body.email,
}];
res.json(data);
}
);
app.listen(port, () => `Server running on port ${port}`);