Passport-Twitter - Error: Failed to find request token in session - node.js

I am using passport-twitter to set up a twitter connect on my site. Users can connect by clicking on 'login' or on 'add new item'. The only difference between the 2 is that if they click on add new item, a modal window is supposed to open once theyre logged in.
To know on button they click, I store the url in req.session.referrer:
// route for twitter authentication and login
app.get('/auth/twitter', function(req, res, next){
req.session.referrer = req.url;
console.log(req.session);
passport.authenticate('twitter')(req, res, next);
});
app.get('/auth/twitter/new', function(req, res, next){
req.session.referrer = req.url;
console.log(req.session);
passport.authenticate('twitter')(req, res, next);
});
// handle the callback after twitter has authenticated the user
app.get('/auth/twitter/callback', function(req, res, next){
var options = {
successRedirect : '/twitter-user/signin',
failureRedirect : '/'
};
console.log(req.session);
if (req.session.referrer && req.session.referrer.indexOf('new') > -1) options.successRedirect = '/twitter-user/new';
passport.authenticate('twitter', options)(req, res, next)
});
Everything works fine in my development environment but once online I get this error message:
Express
500 Error: Failed to find request token in session
at Strategy.OAuthStrategy.authenticate (/app/node_modules/passport-twitter/node_modules/passport-oauth1/lib/strategy.js:142:54)
...
My settings are set up properly in Twitter. Here is what I get with the logs:
For the request:
{ cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
passport: {},
referrer: '/auth/twitter' }
For the callback:
{ cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
passport: {} }
Maybe it could be due to subdomain problem ( http://example.com vs http://www.example.com) as I don't have the pb locally.
How can I fix this?
Many thanks
EDIT: My API key is set up like this (as per this tutorial: http://scotch.io/tutorials/javascript/easy-node-authentication-twitter):
passport.use(new TwitterStrategy({
consumerKey : configAuth.twitterAuth.consumerKey,
consumerSecret : configAuth.twitterAuth.consumerSecret,
callbackURL : configAuth.twitterAuth.callbackURL
},function(token, tokenSecret, profile, done) {
...
});

First if your callback is localhost and you are using express-session make sure the cookie secure option is set to false. e.g
// Express session
let sess = {
secret: 'secret',
resave: true,
saveUninitialized: true,
cookie: {
secure: false,
}
}
You can also change that in production by
if (process.env.NODE_ENV === 'production') {
app.set('trust proxy', 1) // trust first proxy
sess.cookie.secure = true // serve secure cookies
}
If that didn't work then check if you have set the cookie sameSite option to Strict. Change it to Lax. e.g
let sess = {
secret: 'secret',
resave: true,
saveUninitialized: true,
cookie: {
secure: false,
sameSite: 'Lax'
}
}

I got the same Error but solved it.. and here's what my issue was and the solution.
Actuality, it didn't like my redirect url "http:// localhost /auth/twitter/callback". I changed it to "http:// 127.0.0.1 /auth/twitter/callback". In my actual code, I had to keep it as localhost or I'd get errors about a missing token

Related

Can't not set cookie in express-session using node.js

I tried to see if my cookies is working ,so here's my code
const RedisStore = connectRedis(session)
const redisClient = redis.createClient()
app.use(
session({
//name: 'qid',
store: new RedisStore({ //ttl: how long it should last
client: redisClient,
//disableTTL :true, //make sure session last forever
//disableTouch: true, // make sure it does'nt have to update the last time it's ttl
}),
cookie:{
maxAge: 1000*60*60*24*365*10, //10 years
path: "/"
//httpOnly:true, //javascript front end can't access
//sameSite:'none', // csrf
//secure:false
//secure: __prod__ //cookie only works in https
},
saveUninitialized:true, //automatically create a empty session on default
secret: 'some secret', //env
resave: false,
})
)
app.listen(4000,()=>{
console.log('server stared on localhost:4000')
})
app.get('/products', (req,res,next) => {
console.log(req.session);
if(!req.session.userId){
req.session.userId = 1
}else{
req.session.userId = req.session.userId +1
}
console.log(req.session.userId) //test if work
res.send("hello")
})
So here's the thing, when I connect to localhost:4000/products, In the cookie session, I can only see these
But when I print out the results on vscode console, I can see the number is growing like below , so I do have a session, it's just not showing on the browser , can anyone tell me why is that?
server stared on localhost:4000
Session {
cookie: {
path: '/',
_expires: 2031-08-18T12:59:30.827Z,
originalMaxAge: 315360000000,
httpOnly: true
},
userId: 10
}
11
Session {
cookie: {
path: '/',
_expires: 2031-08-18T13:00:37.257Z,
originalMaxAge: 315360000000,
httpOnly: true
},
userId: 11
}
12
So I got a solution after a lot of tests, So if you only set your cookie to same-site:"none" without secure options ,it would be like my situation,but if you want to turn on secure option your endpoint have to be https, so I don't think this was the answer, and you can change to lax or other options it would act normal in your localhost,
Work in local host
lax
(don't set same site)
But due to secure policy https://www.chromium.org/updates/same-site you can't not pass cookie to some certain website (in my case I want to test cookies in my graphql apollo studio) without setting same-site:"none" secure, so I use mkcert to use https in my localhost
https://web.dev/how-to-use-local-https/ , and everything works,
Work
samesite : none
secure : true
https:yourendpoint

Node.js Express does not delete secure cookie

My backend (Node.js + express.js) uses the following code to delete a cookie:
app.get('/logout', function(req, res) {
res.clearCookie('access_token', { domain:'localhost', path: '/', httpOnly: true, secure: true })
.redirect('http://localhost:4200/login')
});
The problem is when I made the cookie secure the previous code no longer deletes the cookie no matter how I visit the url.

Axios isn't sending session data

I've developed an app using React, Mongodb, Node, and Express and i'm using sessions for authentication. On the backend, I can successfully set a cookie a store a userID however when I try to make requests from the react app using axios, the userID session data is not sent.
This is my session config on the backend:
app.use(session({
name: SESS_NAME || "***",
secret: SESS_SECRET || "***",
saveUninitialized: false,
resave: false,
store: new MongoStore({
mongooseConnection: db,
collection: 'session',
ttl: parseInt(SESS_LIFETIME) / 1000 || (60 * 60 * 48) / 1000
}),
cookie: {
sameSite: true,
path: '/',
domain: APP_DOMAIN || 'localhost:4000',
secure: false, //NODE_ENV === 'production',
maxAge: parseInt(SESS_LIFETIME) || 60 * 60 * 48
}
}));
My cors is configured as follows:
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:4000");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Credentials", true);
next();
});
const corsConfig = {
origin:['http://localhost:3000', 'http://localhost:4000' ],
methods:['GET','POST'],
credentials: true,
};
app.use(cors(corsConfig));
after logging in I set the userID in my user Routes, which I confirmed is set by console logging:
req.session.userId = user._id;
This is an example request from my react app
axios.get('/user/auth', { withCredentials: true })
.then(response => {
...
Note that my app is being served on the same domain - I'm using the node app to serve the react app. my folder structure is similar to the following
- APP PARENT FOLDER
-CLIENT //Whole react app
-MODELS
-ROUTES
-SERVER.JS
-PACKAGE.JSON
-NODE_MODULES
I have searched everywhere and tried everything I can think of... no luck. I would appreciate any help!
I've already checked articles on stack overflow and tried to implement the fixes but have had no luck. I've tried the following fixes:
// in my index.js file
axios.defaults.withCredentials = true;
and adding
{ withCredentials: true }
to all of my requests
When I take the userid created at login (ex: 5d6b5d2b09f7d1332543ba90) and manually plug this into the user Route on the backend then everything works fine.
When I console log the session on every request made by the react app it looks like this:
Session {
cookie:
{ path: '/',
_expires: 2019-09-05T05:38:09.657Z,
originalMaxAge: 172800,
httpOnly: true,
sameSite: true,
domain: 'localhost:4000',
secure: false },
}
When it should look like this:
Session {
cookie:
{ path: '/',
_expires: 2019-09-05T05:38:09.657Z,
originalMaxAge: 172800,
httpOnly: true,
sameSite: true,
domain: 'localhost:4000',
secure: false },
userId: 5d6b5c2b03f7d5532543ba90 }

How do I use session and cookies for express.use(express.static('static'))?

I have a question about session cookies over web from express backend. In the front I am using a Vue PWA/SPA that is being mounted on express static via express.use(express.static('static')); to serve the built files.
I did some research that we can attach options to the function with
express.use(cookieParser());
express.use(session({
secret : `${uuid()}`,
proxy: true,
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 1000 * 60 * 30
}
}))
const options = {
dotfiles: 'ignore',
etag: false,
extensions: ['html', 'htm'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function(res, path, stat) {
res.set('Set-Cookie', "myCookie=cookieValue;Path=/");
res.set('x-timestamp', Date.now());
}
}
express.use(express.static('static' , options));
After doing those, hoping I can read myCookie=cookieValue on the browser via document.cookie but I don't see those datra being printed on the page.
I have also tried it with __dirname method as well and then do
app.get("/", function(req, res) {
req.session.fullname = "Oh mi gee";
res.render("index");
});
didn't give me what I want. Is there a way for me to add session/cookies so I can somewhat secure the API calls by passing cookie data on the header for confirmation?
Thanks in advance!
I have figured it out, is to place this express.static at the very end of the express configuration.
before we establish express.static we will want to do
app.use('/path', (req, res, next) => {
req.session.views++;
res.cookie('myCookie', 'cookieValue', {
maxAge: 1000 * 60 * 30
});
console.log(req.session);
next();
})
will transfer the cookies to the client side with the expiry of half an hour.

Staying logged in after logging out with Express and MongoDB

I am having a problem with logging out of my application.
I am using MongoDB to store my sessions.
I log out by using session.destroy and the document gets removed from the collection in the database. However I still remained logged in. Also the cookie in the browser still exists, surely this should expire. I believe my authentication is using the cookie in the browser to check authentication and since that is still there, it keeps me logged in.
Here is my authentication code:
app.js
app.use(session({
secret: 'whatshouldmysecretkeybe',
cookie: {
maxAge: 86400000
},
resave: false,
unset: 'destroy',
saveUninitialized: false,
store: new MongoStore({
mongooseConnection: db
})
}));
loginController.js
// Authenticated Check
exports.requires_login = function (req, res, next) {
if (req.session && req.session.userId) {
return next();
} else {
return res.redirect('/cms/unauthenticated');
return;
}
}
exports.logout = function (req, res, next) {
if (req.session) {
// delete session object
req.session.destroy(function (err) {
if (err) {
return next(err);
} else {
return res.redirect('/cms/');
}
});
}
}
Route file
I put the login_controller.requires_login middleware on the route to check for authentication on every route that needs authentication. I hope this is the best way to do this.
/* GET Login authenticate */
router.get('/users/logout', login_controller.requires_login, login_controller.logout);
/* GET User listing page */
router.get('/users', login_controller.requires_login, user_controller.list);
Thank you.
Looks like the issue was due to mongoose 5 not being fully compatible with connect-mongo.
This github issue explains more:
https://github.com/jdesboeufs/connect-mongo/issues/277
To fix you have to use your mongo url in the url property instead of mongooseConnection.
Example:
app.use(session({
secret: 'whatshouldmysecretkeybe',
resave: false,
unset: 'destroy',
saveUninitialized: false,
store: new MongoStore({
url: YOUR_MONGO_URL
})
}));

Resources