My issue is similar to this one, all answers there didnt help me.
I'm using Passport.js with local strategy (passport-local-mongoose).
The middleware below works on Postman but fails whenever I try from my React client.
exports.isLoggedIn = (req, res, next) => {
console.log(req.user) // undefined with react, but works from postman
if (req.isAuthenticated()) {
return next();
}
}
Here's my app.js:
require('./handlers/passport');
app.use(cors())
app.use(session({
secret: process.env.SECRET,
key: process.env.KEY,
resave: true,
saveUninitialized: true,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
app.use(passport.initialize());
app.use(passport.session());
handlers/passport.js:
const passport = require('passport');
const mongoose = require('mongoose');
const User = mongoose.model('User');
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
user.js (model):
...
userSchema.plugin(passportLocalMongoose, { usernameField: 'email' });
CLIENT CODE:
const url = 'http://localhost:7777/users/<id>';
const config = {
headers: {
'Content-Type': 'application/json',
},
};
axios.put(url, data, config)
.then(res => console.log(res))
.catch(err => console.log(err));
Am I missing something? does passportLocal strategy means that I can't use with an API and a client like my example? Thanks :D
So, after some time I could find an answer:
Server sends SetCookie header then the browser handle to store it, and then the cookie is sent with requests made to the same server inside a Cookie HTTP header.
I had to set withCredentials: true in my client. (axios.js)
const config = {
withCredentials: true,
headers: {
'Content-Type': 'application/json',
},
};
axios.put(url, { page: '123' }, config)
.then(res => console.log('axios', res))
.catch(err => console.log('axios', err));
Then I had CORS problems.
So I added this to my express server:
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
if ('OPTIONS' == req.method) {
res.send(200);
} else {
next();
}
});
Related
here is some problem that i have... i have been tried days to figure it out but nothing make it working.
i have Node.js Express session on backend and there are users, when i make login i set req.session.userId = "userid" and i have middleware that check if req.session.userId exist and then next() so on Localhost everything worked fine but when i hosted my website i can’t access the req.session.userId it's mean the Middleware don’t next()
Frondend hosted: Netlify
Backend hosted: Nodechef
Mysql hosted: Nodechef
i don’t know, maybe i missed something or that i have to made some
changes when hosting...
i hope you guys have solution for me 🙌🏻
index.js
const express = require('express');
const cookieParser = require("cookie-parser");
const session = require('express-session');
const cors = require('cors');
const app = express();
app.use(express.json());
app.use(cookieParser());
app.use(cors({
origin: '***********',
credentials: true
}));
app.all('/', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Credentials", true);
next();
});
app.use(session({
secret: "******",
name: "*****",
saveUninitialized: true,
resave: true,
cookie: {
domain: '*******',
secure: true,
maxAge: 1000 * 60 * 60 * 24 * 365,
}
}))
app.get('/', (req, res) => {
res.send({ msg: "seccess" })
})
app.use('/users', require('./routes/users'))
const PORT = 3000
app.listen(process.env.PORT || PORT, () => {
console.log(`Express server listening on port ${PORT} `);
});
users/login
const router = require('express').Router()
router.post('/login', (req, res) => {
const { userEmail, userPassword } = req.body
db.query(`SELECT * FROM users WHERE userEmail = ?`, userEmail,
(err, result) => {
if (err) {
return res.send({ err: err })
} else {
if (!userEmail || !userPassword)
req.session.userId = user.id
res.send({ msg: "Login Succes", req: req.session, user: user.id })
}
})
});
Middleware
module.exports.onlyLoggedUsers = (req, res, next) => {
if (req.session.userId) {
next()
} else {
res.status(200).send({err:"sensetive content for logged users only, plesae log in"})
}
}
I just added app.enable('trust proxy')
and it is work temporarily, in safari this not work and also on smartphone, if I got to setting in safari and turn of Prevent Cross-Site Tracking it is working so my question is how I can run the application without turn of Prevent Cross-Site Tracking.
I'm working on my contact page for my static website, and normally, it'd post an email message to by Node.js app on Heroku and send me an email. However, Axios isn't posting the email, because I'm not seeing it on the console logs in Heroku.
Right now, I have a domain name, mydomainname.com, linked to my static website on Firebase, while api.mydomainname.com, is linked to my Heroku app.
I changed the Axios.post between '/api/email', 'api.mydomainname.com/api/email', and 'mydomainname.com/api/email', but neither seemed to work. I thought that because my Heroku app and static website are linked to the same domain name, it'd work.
What would I configure Axios.post to?
Here's what I have at the moment:
Relevant Code
ContactPage.js
handleSubmit = (e) => {
e.preventDefault();
if (this.validate()) {
this.setState({
disabled: true,
emailSent: null
});
Axios.post('api.mydomainname.com/api/email', this.state)
.then(res => {
if(res.data.success) {
this.setState({
emailSent: true
});
this.clearForm();
} else {
this.setState({
disabled: false,
emailSent: false
});
}
})
.catch(err => {
console.log(err);
this.setState({
disabled: false,
emailSent: false
});
})
}
}
index.js
const express = require('express'); //Needed to launch server.
const bodyParser = require('body-parser');
const cors = require('cors'); //Needed to disable sendgrid security.
const sendGrid = require('#sendgrid/mail'); //Access SendGrid library to send emails.
sendGrid.setApiKey(process.env.SENDGRID_API_KEY);
const app = express(); //Alias from the express function.
app.use(bodyParser.json());
app.use(cors());
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*'); // Change later to only allow our server
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
app.get('/api', (req, res, next) => {
res.send('API Status: Running');
});
app.post('/api/email', (req, res, next) => {
console.log(req.body);
const msg = {
to: 'my#email.com',
from: req.body.email,
subject: req.body.subject,
text: req.body.message
}
sendGrid.send(msg)
.then(result => {
res.status(200).json({
success: true
});
})
.catch(err => {
console.log('error: ', err);
res.status(401).json({
success: false
});
});
});
app.listen(process.env.PORT || 4000);
This is my console for my static website.
I eventually found out that the connection to api.mydomainname.com was not secure and needed an SSL certificate. So, I registered my domain to Cloudflare.
I am trying to make a post request from my react app to the express server. On making the post request from postman works fine but when I make it from my react app It gives error 500 (Internal server error)
This is my client side code-
function signUpWithEmail(e,email,password,ConfirmPassword,userHandle) {
e.preventDefault();
let params = {
email: email,
password: password,
ConfirmPassword: ConfirmPassword,
userHandle: userHandle
}
let res = axios({
method: 'post',
url: 'http://localhost:3031/signUp/',
data : params,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
'Access-Control-Allow-Origin': '*'
},
validateStatus: (status) => {
return true
},
})
.then(() => console.log('Created'))
.catch((err) => {
console.log(err.message)
})
This is my server code
`const functions = require('firebase-functions');
const express = require('express')
const app = express()
const port = 3031;
const cors = require('cors');
const { signup } = require('./server/users');
const { login, getAuthenticatedUser } = require('./server/users');
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }))
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:3000/");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.use(cors())
app.use(bodyParser.json())
app.get('/', (req, res) => res.send('Hello World!'))
app.post('/signUp',cors(),signup);
app.post('/login', login);
I'm moving a project over to Vue.js and I can't get any of my middleware to check if users are logged in or to check user ownership of things to work. After searching endlessly, I believe that the problem is that the headers I send from my client to server don't contain the passport serialized user or something? How can I make this work?
Here is my login route on the back-end:
router.post("/login", function (req, res, next) {
if (!req.body.username || !req.body.password) {
res.send("Error");
} else if(req.body.username.length > 40 || req.body.password.length > 40){
res.send("Error");
} else if (req.body.username) {
req.body.username = req.body.username.toLowerCase();
next();
}
}, passport.authenticate('local', {
failureRedirect: '/login'
}), function(req, res){
User.findById(req.user.id, function(err, user){
if(err){
res.send("User not found");
} else {
res.send(user.toJSON());
}
})
});
Here is my login page on the client side:
async login () {
const response = await AuthenticationService.login({
username: this.username,
password: this.password,
})
if(response.data == "Error"){
this.$router.push({
name: 'login'
})
} else {
this.$store.dispatch('setUser', response.data._id);
this.$router.push({
name: 'home'
})
}
}
Here is the axios call that AuthenticationService.login is referencing:
login(credentials){
return Api().post('login', credentials);
},
Api comes from:
import axios from 'axios';
export default function(){
return axios.create({
baseURL: `http://localhost:8081/`
});
}
So how do I make the front-end send the right headers to the back-end after a user is authenticated? As you can see, I store the user id in a vuex state, but I don't think that would be safe to use to confirm ownership and whether or not users are logged in, right? Or would it? I could easily just send that over in the requests, is that right? I feel like that's not safe enough, but Idk what I'm talking about.
EDIT: Here is the passport setup in app.js
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());
app.use(flash());
app.use(cookieParser());
app.use(express.session({ //5a6ba876578447262893ac69
secret: "sessionSecret",
resave: false,
saveUninitialized: false
}));
app.locals.moment = require('moment');
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
Your issue is because your frontend and backend are on different domains.
Cookies, which passport.session()/express.session() use to maintain a user session, are scoped to a specific domain.
When you call axios.get() on the protected resource, axios will not send or receive cookies because localhost:8080 is a different domain to localhost:8081.
Try axios.get('/path/to/your/resource', { withCredentials: true }) and axios.post('/login', { username, password }, { withCredentials: true })
This would have been present even without Vue so long as you're using AJAX to make these calls.
requests.js
let axiosConfig = {
withCredentials: true,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': 'http://localhost:3000/',
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE'
}
}
server.js
var express = require('express');
var app = express();
var cors = require('cors');
app.use(cors({credentials: true, origin: 'http://localhost:8080'}))
app.use(cors({credentials: true, origin: 'http://localhost:8080'}))
Just getting into Node & I have read a few questions here on SO regarding this, however, the request body continues to be { 'object Object' : ''}
The server code is :
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.set('port', 1111);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use('/', (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
app.get('/', (req, res) => {
res.send('this is a normal response');
});
app.post('/d*', (req, res) => {
const reqBody = req.body;
console.log(req.body); // console => {`object Object` : ''}
res.send(reqBody);
});
app.listen(app.get('port'), () => console.log('Server instance running on http://localhost:1111'));
The client side function is a simple 'fetch request':
const postRegistrationForm = (userDetails, dispatch) => {
const url = 'http://localhost:1111/d/register';
const config = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: userDetails
};
fetch(url, config)
.then(data => data.json())
.then(res => console.log('rezzz is...', res));
};
You need to stringify any body/object before sending it with fetch.
Try using this config for your fetch:
const config = {
method: 'POST',
headers: {
'Accept': 'application/json'
'Content-Type': 'application/json'
},
body: JSON.stringify(userDetails)
};