I am trying to use express session with react/express frontend and backend. For the express server, I saved the user information in express session in success callback, then I set the credential in the express option and cors to true. However, when I use axios post request from the React frontend with withCredential set to true, req.session.user still shows up as undefined. Does anyone know how to resolve this?
I tried to use middleware, but they were not helpful.
In server.mjs
import express from 'express';
import session from 'express-session';
import mongoose from 'mongoose';
import cors from 'cors';
import User from './db.mjs';
import path from 'path';
import url from 'url';
import bcrypt from 'bcryptjs';
import bodyParser from 'body-parser';
import router from './routes/user.routes.mjs';
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(session({
secret: 'keyboard cat',
cookie: {
maxAge: 600000,
secure: true
},
resave: false,
saveUninitialized: true,
}))
app.use(
cors({
allowedHeaders: ["authorization", "Content-Type"], // you can change the headers
exposedHeaders: ["authorization", 'set-cookie'], // you can change the headers
origin: "*",
credentials: true,
origin: true,
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
preflightContinue: false
})
);
app.options({
origin: true,
credentials: true,
})
app.use('/public', express.static('public'));
app.use('/api', router)
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
// make {{user}} variable available for all paths
app.use((req, res, next) => {
res.locals.user = req.session.user;
next();
});
// logging
app.use((req, res, next) => {
console.log(req.method, req.path, req.body);
next();
});
const login = (email, password, successCallback, errorCallback) => {
// TODO: implement login
const user = User.findOne({'email': email}, function (err, user) {
console.log(err,user)
if (err) {
console.log(err);
errorCallback('USER SEARCH FAILED')
}
else {
if (user === null) {
errorCallback('USER NOT FOUND');
}
else {
bcrypt.compare(password, user.password, (err, passwordMatch) => {
if (err) {
console.log(err);
errorCallback("PASSWORD CHECK FAILED")
}
else {
if (passwordMatch) {
successCallback(user);
}
else {
errorCallback("PASSWORDS DO NOT MATCH");
}
}
});
}
}
});
};
const startAuthenticatedSession = (req, user, cb) => {
// TODO: implement startAuthenticatedSession
console.log('starting new authenticated session', user);
req.session.regenerate(function(err) {
if (!err) {
// set a property on req.session that represents the user
req.session.user = user;
cb(err);
} else {
// call callback with error
cb(err);
}
})
};
const endAuthenticatedSession = (req, cb) => {
// TODO: implement endAuthenticatedSession
req.session.destroy((err) => { cb(err); });
};
const signup = (email, password, errorCallback, successCallback) => {
// TODO: implement register
if (password.length < 8) {
errorCallback('PASSWORD TOO SHORT');
}
User.findOne({'email': email}, function(err, result) {
console.log(result);
if (result === null) {
const hash = bcrypt.hash(password, 10, function(err, hash) {
// do more stuff here!
if (err) {
console.log(err);
errorCallback({message: 'PASSWORD HASH FAILED'})
}
const newUser = new User({
email: email,
password: hash
});
newUser.save(function(err, user, count) {
if (err) {
errorCallback('DOCUMENT SAVE ERROR')
}
successCallback(user);
console.log(req.session.user);
});
});
}
else {
errorCallback('EMAIL ALREADY EXISTS');
}
})
User.findOne({'email': email});
};
app.get("/api", (req, res) => {
res.json({"user": ["userOne", "userTwo", "userThree"]})
})
app.post("/api/login/", (req, res) => {
const email = req.body.email;
const password = req.body.password;
console.log(req.body)// assumes that User was registered in `./db.mjs`
function success(newUser) {
startAuthenticatedSession(req, newUser, (err) => {
if (!err) {
req.session.user = newUser;
res.send({key:'success'});
} else {
res.render('error', {message: 'err authing???'});
}
});
}
login(email, password, success, (e)=>console.log(e));
})
In react frontend component
import '../../App.css';
import React from 'react';
import axios from 'axios';
import icon from '../../img/upload.svg';
axios.defaults.withCredentials = true;
function handleFile(files) {
alert("Number of files: " + files.length);
console.log(files);
const profileImg = 'profileImg';
console.log(files[0].name);
const formData = new FormData();
formData.append(profileImg, files[0]);
axios.post("http://localhost:8000/api/user-profile", formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
withCredentials: true
}).then(res => {
console.log(res);
});
}
console.log for undefined in post request
router.post('/user-profile', upload.single('profileImg'), (req, res, next) => {
const url = req.protocol + '://' + req.get('host')
console.log(req.file);
console.log(req.session.user);
Edit: the console log for req.session:
Session {
cookie: {
path: '/',
_expires: 2022-12-05T04:56:43.020Z,
originalMaxAge: 600000,
httpOnly: true,
secure: true
}
}
Related
Me need set cookie with httlp only in server with using passport js ("Google"), after i set cookie me need redirect but i can't i see this error:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:371:5)
at ServerResponse.setHeader (node:_http_outgoing:576:11)
at ServerResponse.header (H:\1HF_solution\location\server\node_modules\express\lib\response.js:794:10)
at ServerResponse.location (H:\1HF_solution\location\server\node_modules\express\lib\response.js:915:15)
at ServerResponse.redirect (H:\1HF_solution\location\server\node_modules\express\lib\response.js:953:18)
I can only set cookie or redirect but i need both. Help please
Here my code
google-strategy.ts
import passport from 'passport';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
import { IGoogleDto } from '../interfaces/user-interface';
import userService, { IServerData } from '../service/user-service';
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/api/oauth/google/callback',
},
async function (
accessToken: any,
refreshToken: any,
profile: { _json: IGoogleDto },
done: (arg0: any, arg1: boolean | IServerData | { registrationToken: string }, arg2: undefined) => void
) {
try {
const googleDto: IGoogleDto = profile._json;
const result = await userService.findOrCreateForGoogle(googleDto);
'result: {refreshToken:'',userDto:'user data object'}
done(null, result, null);
} catch (err) {
done(err, null, null);
}
}
)
);
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
oauth-router.ts
import { Router } from 'express';
import passport from 'passport';
import { IRTRequest } from '../interfaces/user-interface';
import { IServerData } from '../service/user-service';
require('../strategy/google-strategy');
const router = Router();
const CLIENT_URL = process.env.CLIENT_URL;
router.get('/logout', (req, res, next) => {
req.logout(function (err) {
if (err) {
next(err);
}
});
res.clearCookie('refreshToken');
res.redirect(CLIENT_URL);
});
router.get('/google/success', (req: IRTRequest, res, next) => {
if (req.user) {
res.status(200).json({
success: true,
message: 'successfully',
user: req.user,
});
res.cookie('refreshToken', req.user.refreshToken, {
maxAge: 30 * 24 * 60 * 60 * 1000,
httpOnly: true,
});
}
});
router.get('/google/failed', (req, res) => {
res.status(401).json({
success: false,
message: 'failure',
});
});
router.get(
'/google/callback',
passport.authenticate('google', {
successRedirect: 'success',
failureRedirect: 'failed',
})
);
router.get('/google', passport.authenticate('google', { scope: ['email', 'profile'] }));
In client i call
const GoogleHandler = () => {
window.open(process.env.REACT_APP_GOOGLE_OAUTH_URL, '_self');
};
I try use router.get(url,(req,res)=>{
router.get('/google/callback', async (req: IRTRequest, res, next) => {
return await passport.authenticate(
'google',
{
successRedirect: 'login/success',
failureRedirect: 'failed',
},
async (err, data: IServerData) => {
'set cokkie here and redirect but i have error'
}
)(req, res);
});
Also i try end() but i stay in server url.
P.S. I sovled this problem. For avoid this situation i use cookie, and set my userData and set maxAge 5 minutes, this is not secret info and after this 5 minutes thei will cleared and no one get read this data, but if someone can it is not a problem. In client i just read my cookie and set data using redux-tookit
I have been trying to make an authentication system with passport js and node js and it works perfectly when testing with postman. But when I use the backend with react frontend, the authentication fails. Here is my node js server code:
const port = process.env.PORT || 5000;
const app = express();
app.use(
express.urlencoded({
extended: true,
})
);
app.use(session({
secret: process.env.SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: false,
maxAge: 5184000000
}
}))
app.use(express.json());
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect("mongodb://localhost:27017/taskDB", {
useNewUrlParser: true,
useUnifiedTopology: true
});
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, PATCH, OPTIONS");
next();
});
app.use("/api", routes);
Here is the User model:
const mongoose = require("mongoose");
const user = new mongoose.Schema({
username: String,
password: String,
});
module.exports = mongoose.model("User", user);
Here is my passport config file:
const User = require("../models/User");
const bcrypt = require("bcryptjs");
const localStrategy = require("passport-local").Strategy;
module.exports = function (passport) {
passport.use(
new localStrategy((username, password, done) => {
User.findOne({ username: username }, (err, user) => {
if (err) throw err;
if (!user) return done(null, false);
bcrypt.compare(password, user.password, (err, result) => {
if (err) throw err;
if (result === true) {
return done(null, user);
} else {
return done(null, false);
}
});
});
})
);
passport.serializeUser((user, cb) => {
cb(null, user.id);
});
passport.deserializeUser((id, cb) => {
User.findOne({ _id: id }, (err, user) => {
const userInformation = {
username: user.username,
};
cb(err, userInformation);
});
});
};
Here are my routes:
require("./passportConfig")(passport);
router.post("/login", (req, res, next) => {
passport.authenticate("local", (err, user, info) => {
if (err) throw err;
if (!user) res.json({msg: "Unauthorized"});
else {
req.logIn(user, (err) => {
if (err) throw err;
res.json({msg: "Success"});
console.log(req.user);
});
}
})(req, res, next);
});
router.post("/check-auth", (req, res) => {
if (!req.user){
res.json({ auth: false });
} else{
res.json({ auth: true });
}
})
router.post("/register", (req, res) => {
User.findOne({ username: req.body.username }, async (err, doc) => {
if (err) throw err;
if (doc) res.json({msg: "Unauthorized"});
console.log(doc);
if (!doc) {
const hashedPassword = await bcrypt.hash(req.body.password, 10);
const newUser = new User({
username: req.body.username,
password: hashedPassword,
});
await newUser.save();
res.json({msg: "Success"});
}
});
});
For my app.js file in react frontend:
const [isLoggedIn, setIsLoggedIn] = useState(false);
useEffect(() => {
fetch("http://localhost:5000/api/check-auth", {
method: 'POST',
headers: {
"Content-Type": 'application/json',
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods':'GET,PUT,POST,DELETE,PATCH,OPTIONS'
}
}).then(res => res.json()).then((result) => {
console.log(result.auth);
setIsLoggedIn(result.auth);
});
}, [])
return (
<>
<Routes>
<Route to="/" element={isLoggedIn ? <Home /> : <Signup />} />
</Routes>
In the signup page, I handle a submit like so:
const handleSubmit = async(e) => {
e.preventDefault();
await fetch("http://localhost:5000/api/register", {
method: "POST",
headers: {
"Content-Type": 'application/json',
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods':'GET,PUT,POST,DELETE,PATCH,OPTIONS'
},
body: JSON.stringify({ username: inputEmail, password: inputPassword })
}).then(res => res.json()).then((response) => {
console.log(response.msg);
if (response.msg === "Success"){
navigate("/login");
}
});
}
Finally, for the login component, I handle a submit like so:
const handleSubmit = async (e) => {
e.preventDefault();
await fetch("http://localhost:5000/api/login", {
method: "POST",
headers: {
"Content-Type": 'application/json',
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods':'GET,PUT,POST,DELETE,PATCH,OPTIONS'
},
body: JSON.stringify({ username: inputEmail, password: inputPassword })
}).then(navigate("/"))
}
But after being navigated to the home page, I again go to the signup page since isLoggedIn remains false. Any help regarding how to solve this would be appreciated. Thank you
Trying to make requests and send cookies along with it using React and Express. The requests/responses are working fine. But the cookies are not sent. On the client-side:
import axios from 'axios'
let endPoint = 'http://192.168.1.135:80'
axios.defaults.withCredentials = true;
export async function SubmitPost(username, title, body, time){
let res = await axios.post(`${endPoint}/posts/create`, {username: username, title: title, body: body, time: time})
return res.data
}
The server-side route:
router.post('/create', authenticator.authenticate, async (req, res) => {
let post = new Post({
title: req.body.title,
body: req.body.body,
time: req.body.time,
username: req.body.username
})
post.save().then((doc, err) => {
if (err) {
return res.send(Response('failure', 'Error occured while posting', doc))
}
res.send(Response('success', 'Posted Successfully'))
})
})
And the middleware authenticator:
module.exports.authenticate = (req, res, next) => {
const authHeader = req.headers['authorization']
const token = authHeader && authHeader.split(' ')[1]
if (token == null) {
console.log('No authentication token found')
return res.sendStatus(401)
}
jtoken.verify(token, process.env.SECRET, (err, user) => {
if (err) {
console.log(err)
return res.sendStatus(403)
}
req.user = user
next()
})
}
It returns a 401 with a Token Not Found. I have enabled CORS on express as well as cookie-parser
app.use(cookieparser())
app.use(cors({origin: 'http://localhost:3000', credentials: true}))
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use('/auth', require('./routes/authentication_route'))
app.use('/posts', require('./routes/post_route'))
I am using passport.js specifically the local-strategy for authentication with my next.js application.
Making requests to my data store is fine, and auth, authorization works as well. But I'd like access to the req.user for another route so I can have access to that users._id.
As the passport docs indicate:
By default, if authentication fails, Passport will respond with a 401
Unauthorized status, and any additional route handlers will not be
invoked. If authentication succeeds, the next handler will be invoked
and the req.user property will be set to the authenticated user.
This is my Next.js app's server.js file:
var express = require('express');
require('dotenv').config();
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var cors = require('cors');
var nextJS = require('next');
var session = require('express-session');
var mongoose = require('mongoose');
var MongoStore = require('connect-mongo')(session);
var path = require('path');
var bodyParser = require('body-parser');
var auth = require('./lib/auth');
var HttpStatus = require('http-status-codes');
var compression = require('compression');
var helmet = require('helmet');
var PORT = process.env.PORT || 8016;
var { isBlockedPage, isInternalUrl } = require('next-server/dist/server/utils');
function NODE_ENVSetter(ENV) {
var environment,
environments = {
production: () => {
environment = process.env.MONGODB_URI;
console.log(`We are currently in the production environment: ${environment}`);
return environment;
},
test: () => {
environment = process.env.TEST_DB_DSN;
console.log(`We are currently in the test environment: ${environment}`);
return environment;
},
default: () => {
environment = process.env.DEVELOPMENT_DB_DSN;
console.log(`We are currently in the development environment: ${environment}`);
return environment;
}
};
(environments[ENV] || environments['default'])();
return environment;
}
var db = NODE_ENVSetter('development');
function start() {
const dev = process.env.NODE_ENV !== 'production';
const app = nextJS({ dev });
const server = express();
// const proxy = createProxyMiddleware(options);
app
.prepare()
.then(() => {
mongoose.connect(db, {
useNewUrlParser: true,
useUnifiedTopology: true
});
mongoose.Promise = global.Promise;
mongoose.connection
.on('connected', () => {
console.log(`Mongoose connection open on ${db}`);
})
.on('error', err => {
console.log(`Connection error: ${err.message}`);
});
})
.catch(err => {
console.error(err);
});
server.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', '*'); // enables all the methods to take place
return next();
});
server.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Credentials', true);
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
next();
});
server.use(morgan('dev'));
server.set('view engine', 'html');
server.use(express.static(path.join(__dirname + 'uploads')));
server.use('/uploads', express.static('uploads'));
server.use(cors());
server.use(cookieParser());
server.use(bodyParser.json());
server.use(
session({
secret: 'very secret 12345',
resave: true,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection })
})
);
server.use(bodyParser.urlencoded({ limit: '50mb', extended: false }));
server.use(auth.initialize);
server.use(auth.session);
server.use(compression());
server.use(helmet());
server.use('/users', require('./users'));
Here I've included a log to check the req.user object
server.use((req, res, next) => {
console.log('req.user', req.user);
next();
});
// Redirect all requests to main entrypoint pages/index.js
server.get('/*', async (req, res, next) => {
try {
// #NOTE code duplication from here
// https://github.com/zeit/next.js/blob/cc6fe5fdf92c9c618a739128fbd5192a6d397afa/packages/next-server/server/next-server.ts#L405
const pathName = req.originalUrl;
if (isInternalUrl(req.url)) {
return app.handleRequest(req, res, req.originalUrl);
}
if (isBlockedPage(pathName)) {
return app.render404(req, res, req.originalUrl);
}
// Provide react-router static router with a context object
// https://reacttraining.com/react-router/web/guides/server-rendering
req.locals = {};
req.locals.context = {};
const html = await app.renderToHTML(req, res, '/', {});
// Handle client redirects
const context = req.locals.context;
if (context.url) {
return res.redirect(context.url);
}
// Handle client response statuses
if (context.status) {
return res.status(context.status).send();
}
// Request was ended by the user
if (html === null) {
return;
}
app.sendHTML(req, res, html);
} catch (e) {
next(e);
}
});
// eslint-disable-next-line func-names
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
server.all('*', (req, res, next) => {
next(new AppError(`Can't find ${req.originalUrl} on this server!`, 404));
});
if (process.env.NODE_ENV === 'production') {
server.use(express.static('.next/static'));
server.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '.next/static', 'index.html'));
});
server.listen(PORT, err => {
if (err) throw err;
console.log(
`> Ready and listening on PORT:${PORT} in the ${process.env.NODE_ENV} environment`
);
});
} else {
server.listen(PORT, err => {
if (err) throw err;
console.log(`> Ready and listening on http://localhost:${PORT}`);
});
}
}
start();
And this is my auth file:
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var UserModel = require('../models/UserModel');
passport.use(
new LocalStrategy(
{ usernameField: 'username', passwordField: 'password' },
async (username, password, done) => {
try {
const user = await UserModel.findOne({ username: username }).exec();
if (!user) {
return done(null, false, { message: 'Invalid username!' });
}
const passwordOk = await user.comparePassword(password);
if (!passwordOk) {
return done(null, false, {
message: 'Invalid password!'
});
}
return done(null, user);
} catch (err) {
return done(err);
}
}
)
);
// eslint-disable-next-line no-underscore-dangle
passport.serializeUser((user, done) => done(null, user._id));
passport.deserializeUser(async (id, done) => {
try {
const user = await UserModel.findById(id).exec(); //exec is used to get a real Promise
console.log('user deserialUser', user);
return done(null, user);
} catch (err) {
return done(err);
}
});
module.exports = {
initialize: passport.initialize(),
session: passport.session()
};
And it my /login route:
router.route('/login').post((req, res, next) => {
passport.authenticate('local', (err, user) => {
console.log('user 60', req.user);
console.log('user ', user);
// console.log('res.locals.user ', res.locals.user);
if (!user) {
return res.status(404).send({
msg: [
`We were unable to find this user.`,
`This email and/or password combo may be incorrect.
Please confirm with the "Forgot password" link above or the "Register" link below!`
]
});
}
if (user.isVerified === false) {
return res.status(401).send({
msg: [
'Your username has not been verified!',
'Check your email for a confirmation link.'
]
});
} else {
I made a log to see if user would be on the req object
console.log('req.user in success login route', req.user);
return res.status(200).send({
msg: [`Your have successfully logged in;`, `Welcome to Hillfinders!`]
});
}
})(req, res, next);
});
It appears what fixed my problem was the way I was declaring my routes.
This works:
router.post('/login', passport.authenticate('local'), function(req, res) {
var user = req.user;
if (!user) {
return res.status(404).send({
msg: [
`We were unable to find this user.`,
`This email and/or password combo may be incorrect.
Please confirm with the "Forgot password" link above or the "Register" link below!`
]
});
}
if (user.isVerified === false) {
return res.status(401).send({
msg: [
'Your username has not been verified!',
'Check your email for a confirmation link.'
]
});
} else {
return res.status(200).send({
msg: [`Your have successfully logged in;`, `Welcome to Hillfinders!`]
});
}
});
I was declaring it like this:
router.route('/login').post((req, res, next) => {
passport.authenticate('local', (err, user) => {
console.log('user ', user);
// console.log('res.locals.user ', res.locals.user);
if (!user) {
res.status(404).send({
msg: [
`We were unable to find this user.`,
`This email and/or password combo may be incorrect.
Please confirm with the "Forgot password" link above or the "Register" link below!`
]
});
return;
}
if (user.isVerified === false) {
res.status(401).send({
msg: [
'Your username has not been verified!',
'Check your email for a confirmation link.'
]
});
return;
} else {
res.status(200).send({
msg: [`Your have successfully logged in;`, `Welcome to Hillfinder!`]
});
return;
}
})(req, res, next);
});
Think I saw this syntax in the Express docs and just thought it was cool because of the chaining:
router.route('/login').post((req, res, next)=>{})
There must be some reason to declare it like this instead of the normal way...
Anyway thats' what eventually got me the user from passport to be on the req object \o/, This might also help other libraries that add objects of value to the req object too...
I am successfully authenticating and logging in with the google OAuth API.
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const passportInit = require('./app/routes/auth')
const session = require('express-session');
module.exports = (app, db, passport) => {
app.use(session({secret: "ahskfjdhkjshadkjfhlajsdhlfkj"}));
passportInit(passport)
app.use(passport.initialize());
app.use(passport.session())
app.get('/', (req, res) => {
if (req.session.token) {
res.cookie('token', req.session.token);
res.json({
status: 'session cookie set'
});
console.log(req.session.token);
console.log(JSON.stringify(req.user))
} else {
res.cookie('token', '')
res.json({
status: 'session cookie not set'
});
}
});
app.get('/auth/google', passport.authenticate('google', {
scope: ['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/youtube']
}));
app.get('/auth/google/callback',
passport.authenticate('google', {
failureRedirect: '/' // Fail: To err Page
}),
(req, res) => {
req.session.token = req.user.token;
userString = JSON.stringify(req.user);
userObjectValue = JSON.parse(userString);
userId = userObjectValue['profile'].id;
userName = userObjectValue['profile'].name;
userGivenName = userName.givenName;
const details = {'userId': userId};
db.collection('users').findOne(details, (err, item) => {
if (item == null) {
res.redirect('http://localhost:80/Register.html');
} else {
if(item['rolle'] == 'yt') {
res.redirect('http://localhost:80/YT_Welcome.html');
} else {
res.redirect('http://localhost:80/WT_Welcome.html');
}
}
});
}
);
app.get('/logout', (req, res) => {
req.logout();
req.session.token = null;
res.redirect('/');
});
}
Now I want to make a POST request from my frontend to my NodeJS backend.
Frontend-Request:
function registerWT() {
console.log('registerWT started...')
var rolle = 'wt';
var json = {"rolle": rolle};
$.ajax({
url: 'http://localhost:8000/user',
type: 'POST',
data: JSON.stringify(json),
contentType: 'application/json; charset=utf-8',
dataType: 'JSON',
async: false,
success: function (msg) {
var js = JSON.stringify(msg);
var state = msg['state'];
if (state == true) {
console.log('successfully created new user')
} else {
console.log('failed to create new user')
}
}
});
Backend-API:
var ObjectID = require('mongodb').ObjectID;
const passport = require('passport');
const passportInit = require('./auth');
module.exports = (app, db) => {
app.post('/user', (req, res) => {
console.log("POST USER REACHED!"); // This is printed out...
console.log(req.body.rolle); //is printed out correctly
console.log(req.user); // Is undefined...
if (!req.isAuthenticated()) { return res.send({'error':'unauthorized'}) } //Authentication fails...
console.log(req.user.userId);
console.log(req.userGivenName);
console.log(req.body.rolle);
userId = req.user.userId;
userGivenName = req.user.userGivenName;
userRolle= req.body.rolle;
const details = { userId: userId, userGivenName: userGivenName, rolle: userRolle };
db.collection('users').insert(details, (err, result) => {
if (err) {
res.send({ 'error': 'An error has occurred' });
} else {
res.send(result.ops[0]);
}
});
});
}
From my understanding the user authentication data should be send automaticly with every request I am doing from my frontend to my backend, since I logged in via google before. Is this correct or do I miss to include something in my frontend JS request code?
What is interessting is that after I logged in, I have to trouble with navigating to /user. So there is no problem with manualy doing a get request to this API, where I am also checking for authentication.
app.get('/user', (req, res) => {
if (!req.isAuthenticated()) { return res.send({'error':'unauthorized'}) }
db.collection('users').find({}).toArray((err, item) => {
if (err) {
res.send({'error':'An error has occurred'});
} else {
res.json(item)
}
});
});
But when I am making a Get request with JavaScript, the authentication fails again...
JavaScript get request:
function getTest() {
console.log('YT');
$.ajax({
url: 'http://localhost:8000/user',
type: 'GET',
async: false,
success: function (msg) {
var state = msg['state']; //nehmen den Wert von state aus der JSON
if (state == true) {
console.log('successfully created new user')
} else {
console.log('failed to create new user')
}
}
});
}
Does someone know what I am doing wrong here?
Edit:
My passportInit:
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const keys = require('../../config/keys')
module.exports = (passport) => {
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
passport.use(new GoogleStrategy({
clientID: keys.google.clientID,
clientSecret: keys.google.cientSecret,
callbackURL: keys.google.callback
},
(token, refreshToken, profile, done) => {
return done(null, {
profile: profile,
token: token
});
}));
};
Edit2: Added cors package:
const MongoClient = require('mongodb').MongoClient;
const bodyParser = require('body-parser');
const db = require('./config/db');
const keys = require('./config/keys')
const passport = require('passport');
const express = require('express');
const app = express();
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const cors = require('cors')
const port = 8000;
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors({ origin: 'http://localhost' })); //configuring cors
MongoClient.connect(db.url, (err, database) => {
if (err) return console.log(err)
app.options('*', cors()) // enable pre-flight across-the-board
require('./authenticate')(app, database,passport);
require('./app/routes')(app, database, passport);
app.listen(port, () => {
console.log('We are live on ' + port);
});
});
I finally was able to solve the problem.
No, Browser Plug-in or something like this is needed!
Please see my Code below.
Frontend-Request:
function register() {
var role = 'wt';
var json = {"role": role};
$.ajax({
url: 'http://localhost:8000/user',
type: 'POST',
data: JSON.stringify(json),
contentType: 'application/json; charset=utf-8',
dataType: 'JSON',
xhrFields: {
withCredentials: true
},
crossDomain: true,
async: false,
success: function (msg) {
var state = msg['state'];
if (state == true) {
console.log('successfully created new WT')
location.href = 'http://localhost:80/WT_Welcome.html'
} else {
console.log('failed to create new WT')
location.href = 'http://localhost:80/index.html'
}
}
});
}
Backend Server.js
const MongoClient = require('mongodb').MongoClient;
const bodyParser = require('body-parser');
const db = require('./config/db');
const keys = require('./config/keys')
const passport = require('passport');
const express = require('express');
const app = express();
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const port = 8000;
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
MongoClient.connect(db.url, (err, database) => {
if (err) return console.log(err)
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', "http://localhost");
res.header('Access-Control-Allow-Methods','GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Credentials', true)
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
})
require('./authenticate')(app, database,passport);
require('./app/routes')(app, database, passport);
app.listen(port, () => {
console.log('We are live on ' + port);
});
});
Backend API:
app.post('/user', (req, res) => {
if (!req.isAuthenticated()) { return res.send({'error':'unauthorized'}) } //Authentication fails...
userString = JSON.stringify(req.user);
userObject = JSON.parse(userString)
userId = userObjectValue['profile'].id;
userName = userObjectValue['profile'].name; //not used
userGivenName = userName.givenName;
userRolle= req.body.rolle;
const details = { userId: userId, userGivenName: userGivenName, rolle: userRolle };
console.log(details);
db.collection('users').insert(details, (err, result) => {
if (err) {
res.send({ 'state': false });
} else {
res.send({'state' : true});
}
});
});