i try to create an app using react and nodejs
i'm using express-session and express-mysql-session to store sessions,
It's store session on mysql but note stored on browser cookies. knowing that the response cookies including the session that created from server, knowing also that work just fine on development, but after deploy the application on render i found this problem.
server.js :
const express = require("express");
const app = express();
const cors = require("cors");
const config = require("./config/config");
const mode = process.env.NODE_ENV;
app.use(express.json());
const session = require("express-session");
const sqlSessionStor = require("express-mysql-session")(session);
const dbInfo = config[mode];
const options = {
...dbInfo,
schema: {
tableName: "sessions",
columnNames: {
session_id: "session_id",
expires: "expires",
data: "data",
},
},
};
const sessionStor = new sqlSessionStor(options);
app.use(
session({
name: "auth",
key: "auth",
resave: false,
saveUninitialized: false,
secret: "strongSecretKey",
store: sessionStor,
cookie: {
maxAge: 1000 * 60 * 60 * 24,
},
}),
);
const clientUrl = process.env.CLIENT_URL;
app.use(
cors({
origin: clientUrl,
credentials: true,
}),
);
on login.js file:
exports.login = (req, res) => {
authModel
.login(req.body)
.then((result) => {
req.session.isUser = result.user;
res.send(result);
})
.catch((err) => {
res.send(err);
});
};
on client (react):
async function login() {
const options = {
headers: { "Content-Type": "application/json" },
withCredentials: true,
};
const req = await axios.post(`${VITE_API_KEY}/login`, userInfo, options);
const user = await req.data;
if (user.login) {
//
} else {
//
}
}
response cookies:
screenshot
cookies:
screenshot
this is some solutions that not helpful to me:
i insert httpOnly to true and secure: true and the server does not send any response cookies, that way i'm not inserting this potions on code above.
i try to use sameSite with all values
Related
i am trying to get the response from passport.js from node js to react js,i am sending the access and refresh token once user logi's in with google but i am not sure how to take response from node to react
React Code
const googleAuth = async () => {
window
.open('http://localhost:4000/oauth/google', '_self')
};
Node Code
I can able to verify the user and generate access and refresh token but i am not sure how to get these response in react
passport.use(
new GoogleStrategy(
{
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "/google/callback",
},
async function (accessToken, res, refreshToken, profile, done) {
done(null, profile);
const enteredemail = profile.emails.map((a) => a.value);
const sftoken = await getSfToken();
var configHeaders = {
method: "get",
headers: {
Authorization: `Bearer ${sftoken}`,
"Content-Type": `application/json`,
},
};
const emailcheck = await axios.get(
`URL`,
configHeaders
);
if (emailcheck.data.success === true) {
const logintoken = await axios.get(
"URL"
);
const acctok = logintoken?.data?.access_token;
const url = `URL`;
const res = await axios.post(
url,
{},
{
headers: {
Authorization: `Bearer ${acctok}`,
},
}
);
const refreshTokenURL = `URL`;
const refresTok = await axios.get(refreshTokenURL, {
headers: {
Authorization: `Bearer ${acctok}`,
},
});
console.log("refreshToken", refresTok);
} else {
return null
}
}
)
);
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
I am trying to send a template form node js using nodemailer and express-handlebars but I'm getting the error no such file I have no idea what I'm missing
I'm attaching my index.js down
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const hb = require('nodemailer-express-handlebars')
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json())
const nodemailer = require('nodemailer');
const { google } = require('googleapis');
const path = require('path');
// These id's and secrets should come from .env file.
const CLIENT_ID = 'the id';
const CLEINT_SECRET = 'the secret';
const REDIRECT_URI = 'uri';
const REFRESH_TOKEN = 'the token';
const oAuth2Client = new google.auth.OAuth2(
CLIENT_ID,
CLEINT_SECRET,
REDIRECT_URI
);
oAuth2Client.setCredentials({ refresh_token: REFRESH_TOKEN });
app.post("/api", async (req,res) => {
try{
const accessToken = await oAuth2Client.getAccessToken();
const transport = nodemailer.createTransport({
service: 'gmail',
auth: {
type: 'OAuth2',
user: 'your [enter image description here][1]emial',
clientId: CLIENT_ID,
clientSecret: CLEINT_SECRET,
refreshToken: REFRESH_TOKEN,
accessToken: accessToken,
},
})
const handlebarOptions = {
viewEngine: {
extName: ".handlebars",
partialsDir: path.resolve(__dirname, "emialTemplate"),
defaultLayout: false,
},
viewPath: path.resolve(__dirname, "emialTemplate"),
extName: ".handlebars",
};
transport.use(
"compile",
hb(handlebarOptions)
);
// the data which we going to send
const mailOptions = {
from: req.body.name + '<ummed.gagrana#gmail.com>',
to: 'ummed.gagrana#gmail.com',
subject: req.body.subject,
text: "From:" + req.body.email + "\n Message:" + req.body.message,
// html: '<h2>From:</h2>'+'<h4>'+req.body.email+"</h4> <br>"+"<h2>Message:</h2>"+'<h4>'+req.body.message+"</h4>",
template: 'comeBack'
};
//sending mail
const result = await transport.sendMail(mailOptions);
// checking the result after sending mail
console.log(result)
res.send({hey:"well done you just paased some data"})
} catch (error) {
console.log(error)
}
})
app.listen(3000, () => {
console.log("server up and running on port 3000")
})
This the code I am not sure what I'm missing I'm a beginner in nodejs so please help
I am attaching my work directory path for help
[]
You got a typo. emialTemplate --> emailTemplate
const handlebarOptions = {
viewEngine: {
extName: ".handlebars",
partialsDir: path.resolve(__dirname, "emailTemplate"),
defaultLayout: false,
},
viewPath: path.resolve(__dirname, "emailTemplate"),
extName: ".handlebars",
};
After that, I would return the following code line to tell the server that the code has been processed as it should have.
return res.send({hey:"well done you just paased some data"})
I have my database up and running. The connection is working. I want to store my session in to the database.
Here's my code. When I run the server on my browser I get this error:
RequestError: No connection is specified for that request.
I just kept it simple in one app.js file.
var express = require('express');
var mysql = require('mysql2');
var session = require('express-session');
var MsSQLStore = require('mssql-session-store')(session);
var port = 3000;
var app = express();
var connection = mysql.createConnection ({
host: 'localhost',
user: 'root',
password: '.....',
database: 'node'
});
var sess = {
secret: 'Pearl',
resave: false,
saveUninitialized: true,
store: new MsSQLStore(options)
};
var options = {
connection: connection,
ttl: 3600,
reapInterval: 3600,
reapCallback: function() {console.log('expired sessions were removed');}
};
if(app.get('env') === 'production') {
app.set('trust proxy', 1)
sess.cookie.secure = true
}
app.use(session(sess));
connection.connect();
connection.query('Select 1 + 1 AS solution', (err, rows, fields) => {
if (err) throw err
console.log('the solution is: ', rows[0].solution)
});
app.listen(port, (req, res) => {
console.log('the server is running, ' + ' please, open your browser at http://localhost:%s', port);
});
app.get('/', (req, res) => {
res.end('Hello World');
});
In store: new MsSQLStore(options), you are attempting to use options before you've assigned it a value so it will be undefined when you try to use it. Move the definition and assignment of options to BEFORE you use it.
So, change this:
var sess = {
secret: 'Pearl',
resave: false,
saveUninitialized: true,
store: new MsSQLStore(options)
};
var options = {
connection: connection,
ttl: 3600,
reapInterval: 3600,
reapCallback: function() {console.log('expired sessions were removed');}
};
to this:
const options = {
connection: connection,
ttl: 3600,
reapInterval: 3600,
reapCallback: function() {console.log('expired sessions were removed');}
};
const sess = {
secret: 'Pearl',
resave: false,
saveUninitialized: true,
store: new MsSQLStore(options)
};
Incidentially, if you use let or const for these, then this would have been flagged by the interpreter as an error which is yet another reason to stop using var entirely.
I am implementing a login system for my project. This project is divided in two, a server portion in NodeJS, and a client portion in ReactJS. Both of these are wrapped up in docker containers including a couple more containers for mySQL and PHPMyAdmin. Thus far, I've been able to connect to databases in the mySQL container and insert into a table for Users. Now, I'm trying to log in with a user, then save this user information if the login is successful, and return the session when asked. So I call the sign in get request as follows in the front-end:
export function signIn(table, userName, password) {
return axios.get(`http://localhost:8000/signin`, {
params: {
table,
userName,
password,
},
}, {withCredentials: true}).then((response) => {
if (response.data.length === 1) {
return "success";
}
return response;
});
}
Then in the server, I receive and work with the information like this:
const bcrypt = require('bcryptjs');
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const multer = require('multer');
const mysql = require('mysql');
const nodeMailer = require('nodemailer');
const session = require('express-session');
const smtpTransport = require('nodemailer-smtp-transport');
const app = express();
const upload = multer();
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true,
cookie: {
maxAge: 7 * 24 * 60 * 60 * 1000,
secure: false,
}
}));
app.use(cors(({
credentials: true,
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
const pool = mysql.createPool({
host: process.env.MYSQL_HOST_IP,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
});
app.get('/signin', (req, res) => {
const { table, userName, password } = req.query;
pool.query(`select * from ${table} where username = '${userName}'`, (err, results) => {
if (err) {
res.send(err);
} else {
if (bcrypt.compareSync(password, results[0].password)) {
req.session.userId = results[0].id;
req.session.name = results[0].name;
req.session.email = results[0].email;
req.session.sex = results[0].sex;
req.session.img = results[0].img;
req.session.userName = results[0].username;
req.session.about = results[0].about;
req.session.save(err => console.log(err));
res.send(results);
} else {
res.send([]);
}
}
});
});
Then I expect to call it with another request to get the information back and use to to modify a front end component's state like this (both of these requests are in the same file):
app.get('/loggeduser', (req, res) => {
if (req.session.userId) {
const {
userId,
name,
email,
sex,
img,
userName,
about,
} = req.session;
const userInfo = {
userId,
name,
email,
sex,
img,
userName,
about,
};
res.send(userInfo);
} else {
res.send({});
}
});
and the component calls it like this:
export function getLoggedUser(setUserInfo) {
axios.get(`http://localhost:8000/loggeduser`, {}, {withCredentials: true}).then((response) => {
setUserInfo(response.data);
});
}
But the information never gets sent back, because req.session.userId is always undefined. I tried adding a console.log to output req.session and whenever I refresh the page (at which time the component calls getLoggedUser) the server image outputs req.session with a created time that is just a few seconds ago from the moment I refresh the page, meaning it gets created anew whenever I refresh. Is it that this is not saving properly because it's a get request and not a route? Please let me know if I may be missing something vital for this to work.
I am building an API with Node.js, Express, MYSQL and with the help of sequelize. I am using MVC pattern.
The problem I am encountering however is the server cannot send back any http response after request. When sending a post request for example with postman, the request keeps on loading and will terminate after around 2 minutes with COULD NOT GET ANY RESPONSE exception. While this is happening, data is correctly saved in the database.
This is my AuthController user registration method:
'use strict';
// AuthController.js
var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');
router.use(bodyParser.urlencoded({ extended: false }));
router.use(bodyParser.json());
var jwt = require('jsonwebtoken');
var bcrypt = require('bcryptjs');
const Model = require('../models/index');
const User = Model.sequelize.import('../models/user');
// Register new User.
exports.register = function(req, res) {
var hashedPassword = bcrypt.hashSync(req.body.password, 8);
User.create({
name : req.body.name,
email : req.body.email,
password : hashedPassword
},
function (err, user) {
if (err)
{
return res.status(500).send("There was a problem registering the user. "+err)
}
else{
// create a token
var token = jwt.sign({ id: user._id }, process.env.AUTH0_CLIENT_SECRET, {
expiresIn: 86400 // expires in 24 hours
});
res.status(200).json({ auth: true, token: token });
}
});
};
// App.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
const cors = require('cors');
var app = express();
var indexRoutes = require('./routes/index');
var userRoutes = require('./routes/users');
var courseRoutes = require('./routes/courses');
var authRoutes = require('./routes/auth');
// view engine setup
// Currently I am not using view-templates
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(cors()); //enable CORS
app.use(express.static(path.join(__dirname, 'public')));
//User Routes
app.use('/', indexRoutes);
app.use('/api', userRoutes);
app.use('/api', courseRoutes);
app.use('/api/auth', authRoutes);
// 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');
});
module.exports = app;
//ROUTES
//auth.js
var express = require('express');
var router = express.Router();
//Require Controller Modules
var controller = require('../controllers/AuthController');
//Register new user
router.post('/register', controller.register);
router.get('/user', controller.me);
router.post('/login', controller.login);
router.get('/logout', controller.logout);
module.exports = router;
//User Model
'use strict';
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('User', {
//id: DataTypes.INTEGER,
name: DataTypes.STRING,
email: {type: DataTypes.STRING, allowNull: false, unique: true, validate: { isEmail: {msg: "Invalid Email"} }},
password: DataTypes.STRING
}, {});
User.associate = function(models) {
// associations can be defined here
};
return User;
};
DB Connection //in models/index.js
'use strict';
var fs = require('fs');
var path = require('path');
var Sequelize = require('sequelize');
var basename = path.basename(__filename);
var env = process.env.NODE_ENV || 'development';
var config = require(__dirname + '/../config/config.json')[env];
var db = {};
const Op = Sequelize.Op;
if (config.use_env_variable) {
var sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
var sequelize = new Sequelize(config.database,
config.username,
config.password,
{
host: config.host,
dialect: config.dialect,
operatorsAliases: false,
}
);
//check if connection is established
sequelize
.authenticate()
.then(() => {
console.log('Database Connection has been established successfully.');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
var model = sequelize['import'](path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
I think there is something wrong I am committing or missing out something. I am experiencing this problem when sending POST REQUESTS. Data is saved in mysql table but no response is sent back.
Please assist. Thanks.
Thank you guys for trying to assist. After working around I discovered that problem was with the controller method. The way it was structured was not sending back response after data is persisted in the database.
This is how I recoded my register method in AuthController:
//Old one
// Register new User.
exports.register = function(req, res) {
var hashedPassword = bcrypt.hashSync(req.body.password, 8);
User.create({
name : req.body.name,
email : req.body.email,
password : hashedPassword
},
function (err, user) {
if (err)
{
return res.status(500).send("There was a problem registering the user. "+err)
}
else{
// create a token
var token = jwt.sign({ id: user._id }, process.env.AUTH0_CLIENT_SECRET, {
expiresIn: 86400 // expires in 24 hours
});
res.status(200).json({ auth: true, token: token });
}
//Rewrite:
// Register new User.
exports.register = function(req, res) {
var hashedPassword = bcrypt.hashSync(req.body.password, 8);
User.create({
name : req.body.name,
email : req.body.email,
password : hashedPassword
})
.then(user=>{
// create a token
var token = jwt.sign({ id: user._id }, config.secret, {
expiresIn: 86400 // expires in 24 hours
});
return res.status(200).json({ auth: true, token: token });
}).catch(err=>{
return res.status(500).send("There was a problem registering the user. "+err)
});
};
This worked for me and the code now works as expected.