Next.js, Express.js app's apis running in development but status 404 in production - express

I have deployed nextjs, expressjs application on production but I am getting 404 for all apis.
I have pages that works fine
var session = require('express-session');
var passport = require('passport');
const KnexSessionStore = require('connect-session-knex')(session);
const knex = require('./db/knex.js');
const authMid = require('./config/utils')
const app = express();
app.use(compression())
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
// sesstion
const store = new KnexSessionStore({
knex: knex,
tablename: 'sessions' // optional. Defaults to 'sessions'
});
app.use(session({
name: 'connect.sid',
store: store,
secret: 'somesupersecretkey',
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 7
},
// cookie: { secure: false }
}));
app.use(passport.initialize());
app.use(passport.session());
require("./config/passport");
require("./config/passport_fb");
require("./config/passport_google");
var routes = require('./routes/index');
routes.mp_routes(app);
// Server-side
const route = pathMatch();
// pages set up
// private & public
app.get('/', (req, res) => {
return nextApp.render(req, res, '/index', req.query)
})
app.get('/questions', (req, res) => {
return nextApp.render(req, res, '/questions', req.query)
})
And my routes/index.js file looks like
module.exports.mp_routes = (app) => {
app.use('/api/v1', questionsRoutes),
app.use('/api/v1', answersRoutes)
}
Everything nextjs pages and express apis do work fine in development. I don't have to do anything but on production pages do work but all apis say status 404. How do i get fixed

Related

Passport user object in request not available in getInitialProps when server is on a different port

I have my express server on a different port than my client-side nextjs project.
I know when you have a server on the same port you can use getRequestHandler with next that passes the user object to be accessible with getInitialProps in the client-side.
const express = require("express");
const next = require("next");
const app = next({ dev: true });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
// adds passport session
require("./middlewares").init(server);
const apolloServer = require("./graphql").createApolloServer();
apolloServer.applyMiddleware({ app: server });
server.all("*", (req, res) => {
return handle(req, res);
});
server.listen(port, (err) => {
if (err) throw err;
});
});
My passport implementation is as follows
const config = require("../config");
const session = require("express-session");
const passport = require("passport");
exports.init = (server, db) => {
require("./passport").init(passport);
const sess = {
name: "pid",
secret: config.SESSION_SECRET,
cookie: { maxAge: 2 * 60 * 60 * 1000 },
resave: false,
saveUninitialized: false,
store: db.initSessionStore(),
};
if (process.env.NODE_ENV === "production") {
server.set("trust proxy", 1);
sess.cookie.secure = true;
sess.cookie.httpOnly = true;
sess.cookie.sameSite = 'none';
sess.cookie.domain = process.env.DOMAIN;
}
server.use(session(sess));
server.use(passport.initialize());
server.use(passport.session());
};
And running the following on the express server, I can see req.user returning the user object.
app.use((req, res, next) => {
console.log(req.user);
next();
});
In a page in my nextjs app, in getInitialProps req.user is undefined
Home.getInitialProps = async (ctx) => {
const { req } = ctx;
const { user } = req;
console.log(user);
..........
};
Is there a way to either access the passport user object via SSR in nextjs or a different method to authorize and user on a page?
I do have a Github Repo with instructions on how to run the app in the README.md
Passport auth doesn't seems work across port. The solution is put a ngnix in front.
Local passport authorization on different ports

Connect flash not displaying messages in Pug

I have an application with several routes, and I want to send flash messages of different kinds given the user interaction: either a success or failure message, or in some cases no message. Right now the messages are not displaying and I can't figure out how to get it to work. I'm using Node, Express and Pug.
I have a server.js file, routes.js file, message.pug file, and layout.pug file. Here are my files:
server.js
// init project
const express = require('express');
const app = express();
const bodyparser = require("body-parser");
const flash = require('connect-flash');
const passport = require("passport");
const session = require("express-session");
// http://expressjs.com/en/starter/static-files.html
app.use(express.static("public"));
app.set('view engine', 'pug');
// bodyparser middleware
app.use(bodyparser.urlencoded({ extended: false }));
app.use(bodyparser.json());
// express-session middleware
app.use(session({
secret: process.env.SECRET,
resave: true,
saveUninitialized: true
}));
// express-messages middleware
app.use(flash());
app.use((req, res, next) => {
res.locals.messages = require('express-messages')(req, res);
next();
});
app.use(express.json());
// import passport-config file
require("./passport-config")(passport);
// passport middleware
app.use(passport.initialize());
app.use(passport.session());
const routes = require('./routes.js');
routes(app);
// listen for requests :)
const listener = app.listen(process.env.PORT, () => {
console.log('Your app is listening on port ' + listener.address().port);
});
routes.js
app.get('/', (req, res) => {
req.flash("success", "your flash messages are working");
res.redirect("/admin");
});
app.get("/admin", (req, res) => {
res.render(process.cwd() + '/views/pug/admin');
});
message.pug
.messages
each type in Object.keys(messages)
each message in messages[type]
div(class="alert alert-" + type) #{ message }
// expected output
// div(class="alert alert-success") your flash messages are working
layout.pug
div.col-10.ml-sm-auto.px-4
!= messages('message', locals)
Since I had only two types of messages I was sending -- success or error -- I got rid of my messages.pug file and used the following code, which works.
server.js
// init project
const express = require('express');
const app = express();
const bodyparser = require("body-parser");
const flash = require('connect-flash');
const passport = require("passport");
const session = require("express-session");
// http://expressjs.com/en/starter/static-files.html
app.use(express.static("public"));
app.set('view engine', 'pug');
// bodyparser middleware
app.use(bodyparser.urlencoded({ extended: false }));
app.use(bodyparser.json());
// express-session middleware
app.use(session({
secret: process.env.SECRET,
resave: true,
saveUninitialized: true
}));
// express-messages middleware THIS IS WHAT I CHANGED
app.use(flash());
app.use((req, res, next) => {
res.locals.errors = req.flash("error");
res.locals.successes = req.flash("success");
next();
});
app.use(express.json());
// import passport-config file
require("./passport-config")(passport);
// passport middleware
app.use(passport.initialize());
app.use(passport.session());
const routes = require('./routes.js');
routes(app);
// listen for requests :)
const listener = app.listen(process.env.PORT, () => {
console.log('Your app is listening on port ' + listener.address().port);
});
routes.js (the same as before)
app.get('/', (req, res) => {
req.flash("success", "your flash messages are working");
res.redirect("/admin");
});
app.get("/admin", (req, res) => {
res.render(process.cwd() + '/views/pug/admin');
});
Then in layout, I use the following:
div.col-10.ml-sm-auto.px-4
if successes
for success in successes
div.alert.alert-success #{ success }
if errors
for error, i in errors
div.alert.alert-danger #{ error }
This works for displaying a message in a redirect.
Note: If you want to display a message directly (via res.render()), you have to pass it to the render method directly like this:
app.get('/admin', (req, res) => {
req.flash("success", "flash message for a render method");
res.render("/admin", { successes: req.flash("success") });
});

Apollo express don't have express passport session

For our portal, i integrated my express server with passport to authenticate user. Once user authenticated need to fetch details for user from our api using same session from client. passport authentication working for my portal and able to see identity provider data for user logged in. but when any GraphQL call executed from react side, Apollo servers don't have user session in its request but express had.
Followed the steps mentioned here https://www.apollographql.com/docs/apollo-server/essentials/server.html#ssl but when setting up context for ApolloServer, req don't have passport in its session.
const express = require('express');
const session = require('express-session');
const { ApolloServer } = require('apollo-server-express');
const addResolveFunctionsToSchema = require('graphql-tools').addResolveFunctionsToSchema;
const mongooseConnection = require('./src/persistence/mongooseConnection');
const MongoSession = require('connect-mongo')(session);
const config = require('config');
const mongo = config.get('mongo');
const fs = require('fs');
const https = require('https');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const configSession = config.get('session');
const configPassport = config.get('passport');
const configCommon = config.get('common');
const resolvers = require('./src/resolvers');
const schema = require('./src/schema');
const uri = `${mongo.uri}/${mongo.database}`;
const app = express();
var passport = require('passport');
const SamlStrategy = require('passport-saml').Strategy;
const authRoute = require('./routes/auth');
const apiRoute = require('./routes/userDetails');
const Helmet = require('helmet');
require('reflect-metadata');
mongooseConnection.create();
let mongoOptions = {};
const mongoSessionStore = new MongoSession({
url: `${uri}`,
mongoOptions: mongoOptions,
collection: configSession.mongo.collection
});
addResolveFunctionsToSchema(schema, resolvers);
passport.use(
new SamlStrategy(
{
entryPoint: configPassport.entry_point,
// issuer: 'passport-saml',
protocol: 'https',
callbackURL: `${configCommon.dns}/${configPassport.callback_url}`,
// cert: adfsTokenSigningCert,
identifierFormat: null,
forceAuthn: true,
signatureAlgorithm: 'sha256',
acceptedClockSkewMs: -1
},
(profile, cb) => {
cb(null, profile);
}
)
);
passport.serializeUser(function(user, done) {
done(null, userData);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
app.use(cookieParser());
app.use(
session({
secret: 'project',
secret: configSession.config.secret,
resave: false,
saveUninitialized: false,
store: mongoSessionStore,
sameSite: true,
rolling: true,
name: 'project',
cookie: {
secure: true,
domain: configCommon.cookie_domain
}
})
);
// Initialize Passport
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: false
})
);
// setting up security headers
app.use(Helmet());
app.get('/s/health-check', (req, res) => {
res.send(`I am alive!!!!`);
});
app.use('/s/api', apiRoute);
app.use('/s/auth', authRoute); // API integration
const isDev = process.env.NODE_ENV !== 'prod';
const apolloServer = new ApolloServer({
schema,
resolvers,
context: ({ req }) => {
console.log(req) //req.session don't have passport in it
return {
req
};
}
});
apolloServer.applyMiddleware({
app,
path: '/graphql'
});
apolloServer.installSubscriptionHandlers(app);
https
.createServer(
{
key: fs.readFileSync(`./keys/server.key`),
cert: fs.readFileSync(`./keys/server.crt`)
},
app
)
.listen(process.env.PORT, () => {
console.log('Express server is running on port 9091');
});
// Handle uncaughtException
process.on('uncaughtException', err => {
console.log(err.message);
process.exit(1);
});
Double check that the request is sending the session cookies. I had the same problem, and I was using Graphql Playground as the client, and it disables sending the cookies by default. You can fix it by going to the settings in the top right of the playground, and setting "request.credentials": "same-origin". After I did that I saw the passport session initialized properly.

Can't set a cookie w/ Nuxt.js, Express-Session

I'm new to NUXT and SSR and I've been researching this for a few hours now and I can't seem to figure it out. I'm using JWT to authenticate users in my Nuxt app with a Bearer Token, which is working great until I hit refresh and lose my session.
Now I'm looking to persist sessions using express-session and connect-mongo. I can't get the cookie to set on the client to be included on future requests.
When a user is authenticated:
router.post('/login', function(req, res) {
User.findOne({
username: req.body.username
}, function(err, user) {
if (err) throw err;
if (!user) {
res.status(401).send({success: false, msg: 'Authentication failed. User not found.'});
} else {
// check if password matches
user.comparePassword(req.body.password, function (err, isMatch) {
if (isMatch && !err) {
// if user is found and password is right create a token
var token = jwt.sign(user.toJSON(), config.secret, { expiresIn: 604800 });
req.session.authUser = { 'user': 'Test User' }
return res.json({success: true, token: token, user: user});
} else {
res.status(401).send({success: false, msg: 'Authentication failed. Wrong password.'});
}
});
}
The console.log above shows the authUser in the session.
Session {
cookie:
{ path: '/',
_expires: 2018-04-03T18:13:53.209Z,
originalMaxAge: 60000,
httpOnly: true },
authUser: { user: 'Test User' } }
When I look at my chrome devtools application cookies a connect.ssid hasn't been set and when I console.log(req.session) on future requests the authUser is missing.
My server code is:
// Passport
var passport = require('passport');
var passportJWT = require("passport-jwt");
var ExtractJwt = passportJWT.ExtractJwt;
var JwtStrategy = passportJWT.Strategy;
// Config File
let config = require('./config/settings.js')
// Initialize Express
var app = express();
// CORS-ENABLE
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://127.0.0.1:1337");
res.header("Access-Control-Allow-Credentials", 'true');
next();
});
app.use(cors())
const dbPath = 'mongodb://blogUser:blogUserPassword#localhost:27017/blog'
// Express Session
app.use(session({
secret: 'super-secret-key',
resave: false,
saveUninitialized: false,
store: new MongoStore({ url: dbPath }),
cookie: { maxAge: 60000 }
}))
// File Upload
app.use(fileUpload());
// view engine setup
// app.set('views', path.join(__dirname, 'views'));
// app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// Routes
var index = require('./routes/index');
var users = require('./routes/users');
app.use('/api', index);
app.use('/users', users);
// Passport Config
app.use(passport.initialize());
app.use(passport.session())
// mongoose
const options = {
autoIndex: true, // Don't build indexes
reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect
reconnectInterval: 500, // Reconnect every 500ms
poolSize: 10, // Maintain up to 10 socket connections
// If not connected, return errors immediately rather than waiting for reconnect
bufferMaxEntries: 0
};
console.log(options);
// Localhost Connect
mongoose.connect(dbPath, options).then(
() => { console.log("connected !!!"); },
err => { console.log(err); }
);
Any and all help is appreciated.
If you want to use the server you create the problem with the session is the express router, because change res and req vars so like recommend in nuxt use this.
const express = require('express');
// Create express router
const router = express.Router()
// Transform req & res to have the same API as express
const app = express()
router.use((req, res, next) => {
Object.setPrototypeOf(req, app.request)
Object.setPrototypeOf(res, app.response)
req.res = res
res.req = req
next()
})
You are missing this step
// Create express router
const router = express.Router()
// Transform req & res to have the same API as express
// So we can use res.status() & res.json()
router.use((req, res, next) => {
Object.setPrototypeOf(req, app.request)
Object.setPrototypeOf(res, app.response)
req.res = res
res.req = req
next()
})
The req, res parameters need to be interchanged on the client side
Once you do router.post('/login') and logout
app.use('/api', router)
And that will work perfectly

passportjs TypeError: User.authenticate is not a function

I'm trying to build a small nodejs, express, mongodb app with authentication using passport-local and passport-local-mongoose, however for some reason when entering the middleware for passport in the main app.js file I get this error "TypeError: User.authenticate is not a function"
I tried the authentication by itself in a test project and it worked just fine, so maybe it's something to do with the order of my code but I can't get to what's causing this issue. I've tried several refactors but to no avail.
Below is the code for the app.js and the User Schema , but Here's a link to the project files if needed.
app.js
const express = require('express'),
app = express(),
path = require('path'),
exphbs = require('express-handlebars'),
methodOverride = require('method-override'),
flash = require('connect-flash'),
session = require('express-session'),
bodyParser = require('body-parser'),
mongoose = require('mongoose'),
LocalStrategy = require("passport-local"),
passport = require("passport"),
mongodb = require("mongodb"),
User = require("./models/User");
// Load routes
const ideas = require('./routes/ideas');
const users = require('./routes/users');
// Connect to mongoose
mongoose.connect('mongodb://localhost/diaries');
mongoose.Promise = Promise;
// Handlebars Middleware
app.engine('handlebars', exphbs({
defaultLayout: 'main'
}));
app.set('view engine', 'handlebars');
// Body parser middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Static folder
app.use(express.static(path.join(__dirname, 'public')));
// Method override middleware
app.use(methodOverride('_method'));
// Express session midleware
//PASSPORT CONFIGURATION
app.use(require("express-session")({
secret: "secret",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.use(flash());
// Global variables
app.use(function(req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
next();
});
// Index Route
app.get('/', (req, res) => {
const title = 'Welcome';
res.render('index', {
title: title
});
});
// About Route
app.get('/about', (req, res) => {
res.render('about');
});
// Use routes
app.use('/ideas', ideas);
app.use('/users', users);
const port = process.env.PORT;
app.listen(port, () => {
console.log(`Server started on port ${port}`);
});
User Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const passportLocalMongoose = require("passport-local-mongoose");
// Create Schema
const UserSchema = new Schema({
name:{
type: String,
required: true
},
email:{
type: String,
required: true
},
password:{
type: String,
required: true
},
date: {
type: Date,
default: Date.now
}
});
UserSchema.plugin(passportLocalMongoose, {usernameField: "email"});
mongoose.model('users', UserSchema);
try importing LocalStrategy from require('passport-local').Strategy
like
const LocalStrategy = require('passport-local').Strategy