So I am trying to build a simple login/authorization tool utilizing node.js, passport.js and angular2. My current issue is that while a user can login, the session information doesn't appear to be passed to the front end server or the front end server doesn't pass the passport information back.
When logging in the user appears to get all the way to the portion where the res.send is called, and at that point serialize has been called and req.sessions.passport.user has been set; however, when the user tries to go to an authorized page, while the cookie is there, the passport is missing. While Deserialized is also never called, the middleware is called/appears called. When the middleware gets to the deserializer there is no passport/user attached thus deserialize is never called.
At this point I am wondering if it might be a CORS issue or something with angular2, but I have been working on this for several days and appear to be doing it the suggested way. I have also tried rebuilding it and setting up CORS in multiple ways along with the middleware and I am running out of ideas. I am also using express session but that appears to be working because the cookie I create in that exists.
Session Data at the end of auth but before responding to the site
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true,
secure: false },
passport:
{ user:
anonymous {
username: 'test',
hash: '4024ca40c4372e029459a1d2d52a25b2fc4642f980f6cc948cc4b35f6350adde',
} } }
Session Data after making further requests
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true,
secure: false } }
Relevant Code:
Passport.js
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((users, done) => {
var id=users.username;
db.one('select * from users where username = $1', id)
.then((user) => {
done(null, user);
})
.catch((err) => { done(err,null); });
});
local.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const init = require('./passport');
var promise = require('bluebird');
var options = {
// Initialization Options
promiseLib: promise
};
var hashclient = require('hashapi-lib-node');
const crypto = require('crypto');
var hash = crypto.createHash('sha256');
var pgp = require('pg-promise')(options);
var connectionString = 'postgresql://...';
var db = pgp(connectionString);
const optionsPassport = {};
init();
passport.use(new LocalStrategy(optionsPassport, (username, password, done) => {
db.one('select * from users where username = $1', username)
.then((user) => {
hash.update(password);
var encryptedPassword=hash.digest('hex');
hash = crypto.createHash('sha256');
if (!user) return done(null, false, { message: 'Incorrect username.' });
if (encryptedPassword!=user.password) {
return done(null, false, { message: 'Incorrect information.' });
} else {
return done(null, user);
}
})
.catch((err) => { return done(err); });
}));
helpers.js
function loginRequired(req, res, next) {
if (!req.user) return res.status(401).json({status: 'Please log in'});
return next();
}
Router.js example
const users = require('express').Router();
const auth = require('./auth');
const update = require('./update');
const password = require('./password');
const authHelpers = require('./helpers');
const passport = require('./local');
users.post('/update', authHelpers.loginRequired, update);
users.get('/:userId', authHelpers.loginRequired, single);
users.post('/create', create);
users.post('/auth', passport.authenticate('local'), auth);
app.js
var passport = require('passport');
app.use(cookieParser())
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(session({
secret: 'X+a1+TKXwd26mkiUUwqzqQ==',
resave:true,
saveUninitialized:true,
cookie:{secure:false}
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(function (req, res, next) {
var allowedOrigins = ['http://localhost:3000']
res.header('Access-Control-Allow-Origin', allowedOrigins);
res.header( 'Access-Control-Allow-Headers', 'withCredentials, Access-Control-Allow-Headers, Origin, X-Requested-With, X-AUTHENTICATION, X-IP, Content-Type, Accept, Access-Control-Request-Method, Access-Control-Request-Headers');
res.header( 'Access-Control-Allow-Methods', 'GET, OPTIONS, HEAD, POST, PUT, DELETE');
res.header( 'Access-Control-Allow-Credentials', true);
next();
});
var routes = require('./routes');
app.use('/', routes);
front end http service
getData (url:string, data:any): Observable<any> {
var headers = new Headers({ 'Content-Type': 'application/json', withCredentials: true });
var options = new RequestOptions({ headers: headers });
return this.http.get(url,options)
.map((res: Response): data => res.json())
.catch(this.handleError);
}
The issue was on the front end I was not setting withCredentials to true in the correct location
var options = new RequestOptions({ headers: headers, withCredentials: true });
Related
I am aware that there are there are loads of questions already on this particular topic and I have gone through all of them and none of the solutions have help so I am aware that this may be a local issue or something very obvious that I'm missing, however any help or tips that anyone could provide would be much appreciated.
I am using passport.js to authenticate users in my express app. The authentication doesn't seem to raise any errors and seems to execute correctly as the users are stored in the session data in the db, e.g.
session: {"cookie":{"originalMaxAge":3600000,"expires":"2023-01-18T15:00:13.646Z","secure":false,"httpOnly":true,"path":"/"},"passport":{"user":"63c69e118d89ef5921231f75"}}
Despite this, if I try to access req.user in any of the controller modules, it appears undefined.
I will paste my code below:
app.js
// Declare imported packages and modules
const express = require('express');
const MongoStore = require('connect-mongo');
const passport = require('passport');
const methodOverride = require('method-override');
const session = require('express-session');
const staticDirectory = require('serve-static');
require('dotenv').config({ path: './config/config.env' });
const dbConnect = require('./config/db');
const authRouter = require('./routes/authRoutes');
const moviesRouter = require('./routes/moviesRoutes');
const userRouter = require('./routes/userRoutes');
const errorHandler = require('./middleware/errorHandler');
// Declare variables for server
const HOSTNAME = process.env.HOST || 'localhost';
const PORT = process.env.PORT || 3000;
// Instantiate express app
const app = express();
// Add middleware to instantiated app
app.use(express.json());
app.use(staticDirectory(__dirname + '/public'));
app.use(methodOverride('_method')); // TODO: read about method override
// Add session middleware and declare session parameters
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: { maxAge: 1000 * 60 * 60 },
store: MongoStore.create({
mongoUrl: `${process.env.DB_SERVER}/${process.env.database}`,
collection: 'sessions'
})
}));
// Add passport middleware
app.use(passport.initialize());
app.use(passport.session());
// Add routes to defined endpoints
app.use('/auth', authRouter);
app.use('/user/favourites', userRouter);
app.use('/', moviesRouter);
// Add error-handling middleware
app.use(errorHandler);
// Connect the db
dbConnect();
// Run the server
app.listen({ path: HOSTNAME, port: PORT }, (error) => {
if (error) return console.log(error);
console.log(`Server is running on port ${PORT}...`);
});
passport-config.js
onst LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');
const User = require('../models/User');
// Middleware function to initialise passport
const initialize = (passport) => {
// Defining the fields used to login
const customFields = {
usernameField: 'email',
passwordField: 'password'
};
// Function to determin how authentication is handled
const authenticateUser = async (email, password, done) => {
// Finding user in the db
const user = await User.findOne({ email: email });
if (!user) {
// No user found returns an error
return done(null, false, { message: `No user with email ${email} found` });
}
try {
// Checking password entered for user hashed against the stored hash
if (await bcrypt.compare(password, user.hash)) {
return done(null, user);
} else {
// return an error if the hashes don't match
return done(null, false, { message: 'Password incorrect' });
}
} catch (error) {
return done(error);
}
}
passport.use(new LocalStrategy(customFields, authenticateUser));
// Built-in passport.js method to add user id in session cookie info
passport.serializeUser((user, done) => {
return done(null, user.id);
});
// Built-in passport.js method to extract user id from session to obtain user info
passport.deserializeUser(async (id, done) => {
const user = await User.findOne({ _id: id });
return done(null, user);
})
}
module.exports = initialize;
In my authControllers file, I have tried a couple of options:
exports.login = (req, res, next) => {
try {
// Login using passport authenticate function
passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/'
})(req, res, next);
} catch (error) {
next(error);
}
}
and
exports.login = (req, res, next) => {
try {
// Login using passport authenticate function
passport.authenticate('local', (error, user, info) => {
if (error) return next(error);
if (!user) return res.redirect('/');
req.login(user, (err) => {
if (err) return next(err);
res.redirect('/');
})
})(req, res, next);
} catch (error) {
next(error);
}
}
I have also tried importing cors module and adding
app.use(
cors({
origin: `http://localhost:${process.env.PORT}`,
credentials: true,
})
);
and also adding
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Allow-Credentials", true);
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) {
return res.send(200);
}
next();
});
I have also tried adding { session: true } to the options for passport.authenticate(), switching from express-session to cookie-session, adding bodyParser middleware, adding cookieParser middleware. I checked the order of app.use(session({...})) and the passport functions and tried removing some of the middleware to see if it was interfering. I also tried manually saving the user in the login function and adding the user to res.locals and without results. And also importing passport-config.js after the passport functions:
app.use(passport.initialize());
app.use(passport.session());
const initializePassport = require('./config/passport-config')(passport);
All of which without results.
Sorry for the long question and as I said, any insight on what is going wrong here would be much appreciated. Thanks!
For my project I need to use authentication using ADFS + SAML.
I have followed the code and details as suggested at
http://www.passportjs.org/packages/passport-saml and sample code at https://github.com/gbraad/passport-saml-example
During authentication, the authentication is successful, but req.user is always undefined.
When I tried to print the req, using CircularJSON.stringyfy, I can see all the details inside SAMLResponse -> 'body'.
Here is my code snippet
routes.js
module.exports = function (app,config,passport) {
app.get('/', function (req, res) {
try {
if (req.isAuthenticated()) {
console.log(req.session)
res.send('user authenticated successfully' + req.user.name) // => If I print req using CircularJSON.stringify, I can see all the details.
} else {
//res.send('User not authenticated.')
res.redirect('/login')
}
} catch (error) {
console.log('Error ' + error);
}
});
app.get('/login',
passport.authenticate(config.passport.strategy,
{
successRedirect: '/',
failureRedirect: '/login'
})
);
}
app.js
const express = require('express');
const https = require('https');
const path = require('path');
const passport = require('passport');
const morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
const session = require('express-session');
const errorhandler = require('errorhandler');
const fs = require('fs');
const config = require('./config/config');
console.log('Using configuration', config);
require('./config/passport')(passport, config);
var app = express();
app.use(express.static("public"));
app.set('port', 3000);
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'https://localhost:3000');
// 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(morgan('combined'));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false }));
app.use(bodyParser.json({ type: 'application/*+json' }));
app.use(session(
{
resave: true,
saveUninitialized: true,
secret: 'my_secret',
cookie: {
secure: true,
httpOnly: true
}
}));
app.use(passport.initialize());
app.use(passport.session());
require('./config/routes')(app, config, passport);
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
var my_server = https.createServer(options,app)
my_server.listen(3000);
passport.js
const SamlStrategy = require('passport-saml').Strategy;
module.exports = function (passport, config) {
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (user, done) {
done(null, user);
});
passport.use(new SamlStrategy(
{
path: config.passport.saml.path,
entryPoint: config.passport.saml.entryPoint,
issuer: config.passport.saml.issuer,
},
function (profile, done) {
return done(null,
{
id: profile.uid,
email: profile.email,
displayName: profile.cn,
firstName: profile.givenName,
lastName: profile.sn
});
})
);
};
Thanks for your help.
Let me answer my own question, in case someone finds it useful.
The mistake I was making was in passport.use
When I changed it to following, it worked..
passport.use(new SamlStrategy(
{
path: config.passport.saml.path,
entryPoint: config.passport.saml.entryPoint,
issuer: config.passport.saml.issuer,
cert: config.passport.saml.cert,
},
function (profile, done) {
return done(null,
{
id: profile['nameID'],
email: profile['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'],
displayName: profile['http://schemas.microsoft.com/identity/claims/displayname'],
name: profile['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname'],
lastName: profile['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname']
});
})
);
The Problem
I am setting up my NodeJS & Express App, using Passport for authentication with Google Sign In and Facebook Login. Everything works very well when working on localhost, but when I deploy my app (to Vercel) I can't make the sessions work.
The signin process works very well, and I can see the user information attached to req.session, and req.user contains all user information.
However, right after that, when calling any route, req.user is undefined
The code
//Setting up the app
const express = require('express');
//const https = require('https');
//Bodyparser to handle JSON
const bodyParser = require('body-parser');
//Mongoose to connect to MongoDB
const mongoose = require('mongoose');
//To handle environments
const keys = require('./keys')
//To handle user sessions
var session = require("express-session");
var MongoDBStore = require('connect-mongodb-session')(session);
//Passport to hangle Google Sign In
var passport = require('passport');
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
//Authentication: serialize and deserialize user
passport.serializeUser(function(user, done) {
console.log(`serialize: user:${user}`);
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
console.log(`deserialize user:${user}`)
done(err, user);
});
});
//Authentication: Google Sign In
passport.use(new GoogleStrategy({
clientID: keys.GOOGLE_CLIENTID,
clientSecret: keys.GOOGLE_SECRET,
callbackURL: keys.URL_GOOGLE_CALLBACK
},
function callback(accessToken, refreshToken, profile, done) {
process.nextTick( ()=> {
User.findOne({'googleId': profile.id}, (err,user)=> {
if(err)
return done(err,false);
if(user){
return done(null, user);
}
else{
var newUser = new User();
newUser.googleId = profile.id;
newUser.googleToken = accessToken;
newUser.firstName = profile.name.givenName;
newUser.email = profile.emails[0].value;
newUser.authType = "Google";
newUser.image = profile.photos[0].value;
newUser.save((err)=> {
if(err)
throw err;
return done(null, newUser);
});
}
});
});
}
));
//Importing the models used
const Country = require('./models/country');
const Place = require('./models/place');
const User = require('./models/user');
const Trip = require('./models/trip');
//Starting the app
const app = express();
//Using body parser as global middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }))
//Using cookie bodyParser
app.use(require('cookie-parser')('keyboard cat'))
//Using Cors for routes
//app.use(cors())
//Store for sessions
var storeSessions = new MongoDBStore({
uri: keys.URI_MONGO,
collection: 'sessions'
});
// Catch errors
storeSessions.on('error', function(error) {
console.log(error);
});
//Added but not sure if useful
app.use(cors({credentials: true, origin: true}));
app.set('trust proxy', 1);
//Setting up a session
app.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: false,
proxy: true,
store: storeSessions,
cookie : {
maxAge: 2419200000
}
}));
//Using passport for authentication
app.use(passport.initialize());
app.use(passport.session());
//Solving CORS issues
app.use((req, res, next) => {
let allowedOrigins = ['http://localhost:3000', 'http://localhost:8080', 'mywebsite.com'];
let origin = req.headers.origin;
if(allowedOrigins.indexOf(origin) > -1){
res.setHeader('Access-Control-Allow-Origin', origin);
}
//res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
res.header('Access-Control-Allow-Credentials', true);
next();
});
//Connection to MongoDB
mongoose.connect(keys.URI_MONGO, {useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log('Connection successful!'))
.catch((error) => { console.error(error); });
//The API call from the Google sign in button
app.get('/authgoogle',
passport.authenticate('google', { scope : ['profile', 'email'] }));
//Callback from Google Sign in
app.get('/authgoogleredirect', function(req, res, next) {
passport.authenticate('google', {
scope : ['profile', 'email']
}, function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect(keys.URL_SIGN_IN); }
req.logIn(user, function(err) {
if (err) { return next(err); }
req.session.user = req.user;
req.session.save(function(){
console.log(`req.session.user in callback: ${req.session.user}`)
console.log(`req.session in callback: ${JSON.stringify(req.session)}`)
res.redirect(keys.URL_LOGGED_IN);
});
});
})(req, res, next);
});
//Middleware to check if user is logged in
function isLoggedIn(req, res, next) {
console.log(`req.session in isloggedin: ${JSON.stringify(req.session)}`);
console.log(`req.user in isloggedin: ${JSON.stringify(req.user)}`);
if (req.isAuthenticated()) {
next();
} else {
data = {
"redirect": true,
"url": keys.URL_SIGN_IN
}
res.send(JSON.stringify(data));
}
}
//--------------------USERS------------------------
//Getting the currently logged in user
app.get('/getcurrentuser', isLoggedIn, function(req, res, next) {
res.send(req.user);
});
What works and what does not
The google sign in works well, and passport.serialize and passport.deserialize work well, I can see the user object.
When I try to reach GET /getcurrentuser (call on all pages), I don't get the req.user object and isAuthenticated() always returns false.
These are the logs of the middleware isloggedin :
req.session in isloggedin: {"cookie":{"originalMaxAge":2419200000,"expires":"2020-08-07T12:09:54.220Z","httpOnly":true,"path":"/"}}
req.user in isloggedin: undefined
The sessions are correctly saved in the session collection in mongoDB.
Serialize and deserialize don't seem to be called after sign in, not sure if that's normal.
What I tried
I read plenty of answers to similar problems but none seem to work:
order of initialization of passport and express session: it should be correct
proxy: added but did not change anything
credentials: include has always been included in my front end fetch call
cookie.secure: false: turned it on and off, without success
cookie session tried to use it instead of express session, without success
It must be something stupid but I can't seem to find it...
What troubles me is why would this work on localhost?
Thanks a lot for your time :)
Alright, if anyone comes across this exact issue, I finally solved it:
req.user always came as undefined, because my front end and back end have different domain names (I'm using the free heroku tier) therefore the cookie was considered third-party, blocked by Google Chrome and never sent to my express app!
As soon as I disabled third-party cookie blocking in Chrome settings the session became persistent!
The passport and session configurations were correct all along...
Thanks #abhinav for your help and time :)
Passport has its own session handling code embedded in its library, if you want to store your passport login user to session-database you can do
router.get("/redirect", passport.authenticate('google',{failureRedirect:'/fail',successRedirect:'/success'}, (req,res)=>{
req.session.user = req.user;
});
and keeping your remaining code same as you have done, this will save your session in the database
Currently a user can sign in with github, and i can see it gets the req.user in the callback function, and on passport github file
console.log(`frontid ${req.user.id}`) // logs user id
and passport
console.log(`backbro ${id}`); // logs an id
however, when i go on this route, the github user returns null and im not sure why. There were a few times, i see the signed in github user return in the current_user route, however its rare that i see it now. It sometimes shows, sometimes dont. Kinda wierd. Could it be a session issue ?
router.get("/current_user", (req, res) => {
if(req.user){
res.status(200).send({ user: req.user});
} else {
res.json({ user:null})
}
});
yes i looked at the following links, still no suitable answer.
Node + Express + Passport: req.user Undefined
req.user undefined after twitter authentication using express sever, passport.js
The way im accessing this link, is by explictily calling
localhost:8000/api/users/auth/github
in the address bar.
routes/users
router.get('/auth/github', passport.authenticate('github', {
scope:[ 'profile', 'id']
}));
router.get('/auth/github/callback',
passport.authenticate('github', { session:true, failureRedirect: 'http:localhost:8001/signIn' }),
function(req, res) {
// Successful authentication, redirect home.
// var token = jwt.sign({ id: req.user.id}, process.env.JWT_SECRET );
// // res.cookie("jwt", token, { expires: new Date(Date.now() + 10*1000*60*60*24)});
// jwt.verify(token, process.env.JWT_SECRET, function(err, data){
// console.log(err, data);
// })
const user = req.user
req.logIn(user, err => {
models.User.findOne({
where: {
id: req.user.id,
},
}).then(user => {
const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET);
// res.cookie("jwt", token, { expires: new Date(Date.now() + 10*1000*60*60*24)});
jwt.verify(token, process.env.JWT_SECRET, function(err, data){
console.log(err, data);
})
res.redirect('http://localhost:8001');
// console.log(req.user)
});
});
console.log(`frontid ${req.user.id}`)
// res.redirect('')
// console.log('this works', token);
});
passport-github.js
const GitHubStrategy = require('passport-github2').Strategy;
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
const models = require("../models/");
// passport.serializeUser((user, done) => {
// // push to session
// done(null, user.id);
// console.log(user.id)
// });
// passport.deserializeUser((id, done) => {
// models.User.findOne({
// where: {
// id,
// },
// }).then(user => done(null, user))
// .catch(done);
// });
module.exports = async (passport) => {
passport.use(
new GitHubStrategy(
{
clientID: process.env.clientID,
clientSecret: process.env.secret,
callbackURL: 'http://127.0.0.1:8000/api/users/auth/github/callback',
passReqToCallback: true,
profileFields: ['id', 'login']
},
(req, accessToken, refreshToken, profile, done) => {
const { id, login, email} = profile._json;
console.log(`backbro ${id}`);
// console.log(req)
models.User.findOne({
where:{
id: id
}
}).then( user => {
// if user is found
if(user){
return done(null, user)
}
// else create new user
else{
models.User.create({
id: id,
username:login,
email: email,
createdAt: Date.now()
}).then( user => {
console.log('github user created');
return done(null, user);
})
}
})
}
)
);
passport.serializeUser((user, done) => {
// push to session
return done(null, user.id);
});
passport.deserializeUser((userId, done) => {
// console.log('calling deserial' + userId);
// // TODO: findByPk syntax? findById deprecated? Try later after sucessfully record data in DB
models.User
.findOne({ where: { id: userId } })
.then(function(user){
// console.log(user);
return done(null, userId);
}).catch(function(err){
done(err, null);
});
// return done(null, id);
});
}
app.js
const express = require('express');
const app = express();
const userRoute = require('./routes/users');
const postRoute = require('./routes/posts');
const bodyParser = require('body-parser');
const logger = require('morgan');
const session = require('express-session');
const cookieParser = require('cookie-parser') ;
const dotenv = require('dotenv');
const env = dotenv.config();
const cors = require('cors');
const models = require('./models/');
const host = '0.0.0.0';
const PORT = process.env.PORT || 8000;
const passport = require('passport');
const path = require('path');
const Sequelize = require('sequelize');
const SequelizeStore = require('connect-session-sequelize')(session.Store);
const proxy = require('express-http-proxy');
app.use(function(req, res, next) {
res.locals.user = req.user; // This is the important line
// req.session.user = user
console.log(res.locals.user);
next();
});
app.use(cors({
origin: process.env.ALLOW_ORIGIN,
credentials: false,
allowedHeaders: 'X-Requested-With, Content-Type, Authorization',
methods: 'GET, POST, PATCH, PUT, POST, DELETE, OPTIONS',
exposedHeaders: ['Content-Length', 'X-Foo', 'X-Bar'],
}))
var sequelize = new Sequelize(
process.env.POSTGRES_DB,
process.env.POSTGRES_USER,
process.env.POSTGRES_PASSWORD,{
"dialect": "sqlite",
"storage": "./session.sqlite"
});
myStore = new SequelizeStore({
db:sequelize,
})
if (!process.env.PORT) {
require('dotenv').config()
}
// console.log(process.env.DATABASE_URL);
if (!process.env.PORT) {
console.log('[api][port] 8000 set as default')
console.log('[api][header] Access-Control-Allow-Origin: * set as default')
} else {
console.log('[api][node] Loaded ENV vars from .env file')
console.log(`[api][port] ${process.env.PORT}`)
console.log(`[api][header] Access-Control-Allow-Origin: ${process.env.ALLOW_ORIGIN}`)
}
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'build')));
// We need a store in order to save sessions, instead of the sessions clearing out on us :)
require('./config/passport')(passport); // PASSPORT Init
require('./config/passport-github')(passport); // PASSPORT Init
app.use(cookieParser());
app.use(bodyParser.json());
app.use(session({
store: myStore,
saveUninitialized: false,
resave:false,
cookie: { maxAge: 30 * 24 * 60 * 60 * 1000 }, // 30 days
secret : process.env.JWT_SECRET,
}));
myStore.sync();
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.urlencoded({ extended:false}));
// this code may be useless or useful, still trying to understand cors.
app.use('/api/users', userRoute );
app.use('/api/posts', postRoute );
// In order to use REACT + EXPRESS we need the following code, alone with a build
// in the client folder we run a npm run build in the client folder then it is referred
// in the following code.
app.use(express.static(path.join(__dirname, 'client/build')));
if(process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, 'client/build')));
//
app.get('*', (req, res) => {
res.sendfile(path.join(__dirname = 'client/build/index.html'));
})
}
//build mode
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname+'/client/public/index.html'));
})
models.sequelize.sync().then(function() {
app.listen(PORT, host, () => {
console.log('[api][listen] http://localhost:' + PORT)
})
})
My Question is similar to this.I am using express version 4.14.0 and I have implemented OAuth2 SSO using "passport-ping" module. For getting new Access token from refresh token which we have on successful login I am using "passport-oauth2-refresh" module. No problem with these modules. Everything works fine as expected. But the problem is with request.user object. Below is my code
var express = require('express');
var async = require('async');
var cookieParser = require('cookie-parser');
var request = require('request');
var passport = require('passport');
var OAuth2Strategy = require('passport-ping').Strategy;
var refresh = require('passport-oauth2-refresh');
var session = require('express-session');
var bodyParser = require('body-parser');
var Client = require('node-rest-client').Client;
var client = new Client();
var _outputpath = "/build",
_templatePath = "./templates";
var app = express();
app.use(express.static(__dirname + "/"));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(session({
secret: "session secret",
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
var port = process.env.port || 8080;
// Allow cross orgin
app.all('*', function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Origin, Content-Type, X-Auth-Token');
res.setHeader('Access-Control-Allow-Credentials', true);
if (req.method === 'OPTIONS') {
res.status(200);
res.end();
} else {
next();
}
});
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (id, done) {
done(null, id);
});
var strategy = new OAuth2Strategy({
authorizationURL: 'xxx',
tokenURL: 'xxx',
clientID: 'xxx',
clientSecret: 'xxx',
callbackURL: 'http://localhost:8080'
},
function (accessToken, refreshToken, profile, done) {
done(null, { accessToken: accessToken, refreshToken: refreshToken });
}
);
passport.use('oauth-provider', strategy);
refresh.use('oauth-provider', strategy);
var isAuthenticated = function (req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.redirect('/');
}
}
/***************** GET BASE PAGE ************/
app.get('/guide', isAuthenticated, function (req, res) {
async.series({
one: function (callback) {
newAccessToken(req, res, true, function (reqQuery) {
var _reqQuery = reqQuery;
res.cookie('userAccessToken', req["user"].refreshToken, { maxAge: 1 * 24 * 3600000, httpOnly: false });
res.sendFile(__dirname + _outputpath + '/index.html');
callback(null, req["user"]);
})
},
two: function (callback) {
callback(null, 2);
}
},
function (err, results) {
console.log('Completed Guide Page');
});
});
app.get('/', passport.authenticate('oauth-provider', {
successRedirect: '/guide',
failureRedirect: '/error',
pfidpadapterid: 'OAuthAdapterCCDS'
})
);
function newAccessToken(req, res, isParent, callback) {
refresh.requestNewAccessToken('oauth-provider', req["user"].refreshToken, function (err, accessToken, refreshToken) {
var expireAccessToken = new Date();
expireAccessToken.setMinutes(expireAccessToken.getMinutes() + 59);
req["user"].refreshToken = refreshToken;
req["user"].accessToken = accessToken;
req["user"].accessTokenTime = new Date();
req["user"].expireAccessToken = expireAccessToken;
callback(req);
});
}
/***************** START THE SERVER ************/
app.listen(port, function () {
console.log('Server started & listening on port: ' + port);
});
On successful login OAuth2Strategy done function is adding below object to req.user.
{ accessToken: accessToken, refreshToken: refreshToken }
On every request I am hitting newAccessToken function to get new Access token for refresh token we have and updating the req.user object with new Access token and refresh token manually as shown below. Is there any better way to update the req["user"]?
req["user"].refreshToken = refreshToken;
req["user"].accessToken = accessToken;
req["user"].accessTokenTime = new Date();
req["user"].expireAccessToken = expireAccessToken;
If the user hits refresh continuously from browser, I am getting as req.user undefined. Tried few things by seeing forum but it dint worked. Any help is much appreciated.
I dint handled the error properly while getting the new access token. I changed new Access token function as below
function newAccessToken(req, res, isParent, callback) {
refresh.requestNewAccessToken('oauth-provider', req["user"].refreshToken, function (err, accessToken, refreshToken) {
var expireAccessToken = new Date();
expireAccessToken.setMinutes(expireAccessToken.getMinutes() + 59);
req["user"].refreshToken = refreshToken;
req["user"].accessToken = accessToken;
req["user"].accessTokenTime = new Date();
req["user"].expireAccessToken = expireAccessToken;
callback(req);
});
}