Express cookie-session not creating cookie on client side - node.js

I have a simple ExpressJS app that is using cookie-session to create a cookie. I have a few routes defined but none are returning a cookie. The documentation for cookie-session says that req.session needs to be altered to set the cookie, which is what I'm doing, but it's not working. I'm not seeing any cookie in when I inspect the Application cookies in Chrome. My app looks like this:
const express = require('express');
const cookieSession = require('cookie-session');
const { v4: uuid } = require('uuid')
const app = express();
app.use(express.json())
app.use(cookieSession({
name: 'shortlinks',
keys: [process.env.SESHSECRET],
maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
}))
app.use(function(req, res, next) {
console.log(`${req.method} ${req.url}`);
req.session.id = (req.session.id || uuid());
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', '*');
next();
})
app.get(
'/api/links',
(req, res, next)=> {
res.json(readDb());
next();
}
)
What do I have to do to have the cookie created?

i hade the same probleme , and i used 'cookies' library i worked well for me...
https://www.npmjs.com/package/cookies
1.npm uninstall cookie-session
//for deleting the old one
2.npm install cookies
//install cookies
and then use it like that
const Cookie = require('cookies')
//inside your route set the token
const cookie = new Cookie(req ,res ,{})
cookie.set('token',accessToken{signed:false,secure:false,httpOnly:true})
//get the token back
const token = cookie.get('token',{signed:false})
console.log(token)

Related

Nodejs server doesn't recognize saved cookie sessionId

I have a nodejs/express server with the following code
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cookieparser = require("cookie-parser");
const { randomBytes } = require('crypto');
const COOKIE_SECRET = 'aavslrhe158ewuycvasjy7et2hvh2ytt0';
var SESSIONS = {};
app.use(
express.static(__dirname + '/public'),
bodyParser.urlencoded({ extended: false }),
bodyParser.json(),
cookieparser(COOKIE_SECRET)
);
app.get("/login", function (request, response){
response.sendFile(__dirname + "/views/login.html");
});
app.post("/verifyaccount", function (request, response){
const nextSessionId = randomBytes(16).toString('base64');
response.cookie("sessionId", nextSessionId, { maxAge: 3600, httpOnly: true, Secure: true });
SESSIONS[nextSessionId] = request.body.sz_Username;
response.status(response_status).redirect('/admin');
}
app.get("/admin", function (request, response){
if(!is_authorized(request.cookies.sessionId)){
response.redirect('/login');
}
else{
response.sendFile(__dirname + "/views/admin.html");
}
});
app.post("/addproject", function(request, response){
if(!is_authorized(request.cookies.sessionId)){
response.redirect('/login');
}
else{
}
}
function is_authorized(sessionId){
var authorized = false;
if (SESSIONS[sessionId]) {
authorized = true;
}
return authorized;
}
So when I login the credentials go to /verifyaccount, there I check if they're correct. Then it creates a cookie in my browser: sessionId:"KlS6xuspQ4GczVqqpSc2Nw%3D%3D" and stores it in the SESSIONS variable. I get redirect to /admin where the authorization works.
But when I am in admin.html and send data to /addproject I get redirect to /login because the authorization fails. The request.cookies.sessionId is undefined. The cookie keeps existing in my browser, so I don't know what the problem is, since the cookie was correct in /admin.
Edit: after being redirect to /admin from /login if I go back to /login or / and then attempt to /admin from the url I get the same undefined error. Which should not occur since the cookie expires in 1 hour.
"maxAge is in milliseconds. Your cookie is expiring 3.6 seconds after you set it"
-clubby789 htb

Setting single cookie with multiple values

I am trying to set a single cookie key-value pair with multiple values in nodeJS. The reason for the single cookie is that I'm sending Token and Secret variables that are linked as part of authentication, separating these out over two cookies may cause issues. I followed a tutorial that suggests stingify method.
When tested in Postman, the cookie seems to be encoded with token and secret. i.e. '%7B%22' etc. Is this as expected, if yes how do I parse values when the cookie is sent to server.
// userToken and mySecret test values.
CustomerRoute.post('/login', (req, res) => {
...
...
var mycookie = JSON.stringify({userToken:1234,mySecret:5678});
res.cookie('ID', mycookie, {HttpOnly:true, maxAge:20*60*1000, sameSite: 'strict'});
res.apiSuccess(resInfo);
Cookie in postman:
ID=%7B%22userToken%22%3A1234%2C%22mySecret%22%3A5678%7D; Path=/; Domain=localhost; Expires=Tue, 02 Mar 2021 17:37:24 GMT;
UPDATE -
I also managed to send the two tokens without stingify by simply concatenating the two strings.
var mycookie = 'Token='+'1234'+'Secret='+'5678';
UPDATE2
I'm using cookie-parser. When I call route:
.post('/data1', (req, res) => {
//var rc = req.headers.cookie;
const { cookies } = req;
console.log(cookies);
res.apiSuccess();
In console I get:
{ ID: '{"userToken":1234,"mySecret":5678}' }
Whats the best method to split values to variables?
UPDATE3 - As a recap. I want to write a single cookie with userToken and mySecret, then in the /data route verify (this will eventually form a function in middleware)
const http = require('http');
const https = require('https');
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
var cookieParser = require('cookie-parser')
const config = require('./config');
var corsOptions = {
origin: 'http://example.com',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
/* init server */
const server = express();
/* middleware */
server.use(express.json());
server.use(cookieParser());
server.use(express.static('public'))
server.use(bodyParser.json({
limit: "10000kb"
}));
server.use(bodyParser.urlencoded({
extended: true,
limit: "10000kb"
}));
server.use(function (req, res, next) {
res.apiError = function (message) {
res.json({
status: false,
message: message
})
};
res.apiSuccess = function (data) {
res.json({
status: true,
data: data
})
};
next();
})
Create cookie - login function
var mycookie = JSON.stringify({userToken:1234,mySecret:5678});
res.cookie('session_id', mycookie, {HttpOnly:true, maxAge:20*60*1000, sameSite: 'strict'});
Read cookie:
CustomerRoute.post('/data1', (req, res) => {
// var rc = req.headers.cookie;
const { cookies } = req;
console.log(cookies);
if ('session_id' in cookies) {
console.log('Session Id exists');
var points = JSON.parse(cookies);
//console.log(cookies['id']);
console.log(points);
}
res.apiSuccess();

How to send firebase session cookie from server to frontend

The problem that I am facing is that the session cookies created on the server seem to not be available on the browser. I'm using firebase session cookies which can be found here: ( https://firebase.google.com/docs/auth/admin/manage-cookies )
Below is the code I have
Server
index.js
const express = require('express');
const cors = require('cors');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
app.use(cors());
app.use(express.urlencoded({extended: true}));
app.use(express.json());
user.js
userRouter.post('/sessionLogin', (req, res) => {
console.log("Got session login request");
// Get the ID token passed and the CSRF token.
const idToken = req.body.idToken.toString();
// Set session expiration to 5 days.
const expiresIn = 60 * 60 * 24 * 5 * 1000;
fb.auth().createSessionCookie(idToken, {expiresIn})
.then((sessionCookie) => {
const options = {maxAge: expiresIn, httpOnly: true, secure: true};
res.setHeader('Cache-Control', 'private');
res.cookie('__session', sessionCookie, options);
return res.send(JSON.stringify({status: 'success'}));
}).catch((error) => {
res.status(401).send('UNAUTHORIZED REQUEST!');
});
});
Frontend
fb.auth.signInWithEmailAndPassword(email, password).then(user => {
return user.user.getIdToken().then(idToken => {
console.log(idToken);
//document.cookie = '__session=' + idToken + ';max-age=3600';
return ref.postIdTokenToSessionLogin(idToken);
});
})
When I use postman I'm able to see the session created as expected
postman session picture
My server and frontend are hosted on different domains. I can't seem to wrap my head around this any ideas would be highly appreciated.
Thanks,
You cannot share cookies across domains (unless they are subdomains). See Cross-Domain Cookies for a related discussion.

How to get a PUT route to work correctly (and not return 404 error) with Axios and Express?

I have an app that makes this call:
handleUpdate (id, data) {
const url = "/sites/" + id;
axios.put(url, data)
.then(res => {
// handling of response
})
.catch(console.error);
}
The route in the server.js file is:
router.route('/sites/:site_id')
.put(function(req, res) {
// handling of update
})
However, every time I make the handleUpdate call, I receive this message:
xhr.js:178 PUT http://localhost:3000/sites/5a39783d09ba9fec39b34d37 404 (Not Found)
The id is correct, but I'm clearly not doing something right.
Below is the applicable portion of the server.js:
//server.js
'use strict'
//first we import our dependencies...
var express = require('express');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
//and create our instances
var app = express();
var router = express.Router();
//set our port to either a predetermined port number if you have set
it up, or 3001
var port = process.env.API_PORT || 3001;
//db config
var mongoDB = // my mlab database connection info;
mongoose.connect(mongoDB, { useMongoClient: true })
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
//now we should configure the API to use bodyParser and look for JSON
data in the request body
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
//To prevent errors from Cross Origin Resource Sharing, we will set our
headers to allow CORS with middleware like so:
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods',
'GET,HEAD,OPTIONS,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-
Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-
Request-Method, Access-Control-Request-Headers');
//and remove cacheing so we get the most recent comments
res.setHeader('Cache-Control', 'no-cache');
next();
});
//now we can set the route path & initialize the API
router.get('/', function(req, res) {
res.json({ message: 'API Initialized!'});
});
You need to use method-override package in order to handle the put request:
1- install method-override package
npm install method-override --save
2- use it in your app
var express = require('express')
var methodOverride = require('method-override')
var app = express()
// override with the X-HTTP-Method-Override header in the request
app.use(methodOverride('X-HTTP-Method-Override'))
3- catch put request
router.route('/sites/:site_id').put(function(req, res) {
// handling of update
})
4- ajax
var config = {
headers: {
'X-HTTP-Method-Override', 'PUT'
}
}
axios.post(url, data, config)
.then(res => {
// handling of response
})
.catch(console.error);
I realized at long last that I was directing the PUT request to the main app and not to the api. Once I corrected for this, it worked perfectly.
How obvious errors seem once they've been solved.
Thanks to everyone who helped out.

Cross domain session authentication with Node.js, Passport, Backbone

I am using Node.js with express server, and passport package for authentication. Client is on same server, different domain built on Backbone.js. The session is created on login request, but if another request comes from client side, I don't manage to access the session.
Node server configuration:
var express = require( 'express' ),
path = require( 'path' ),
mongoose = require( 'mongoose' ),
passport = require('passport'),
cors = require('cors');
app.configure( function() {
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({
secret: secret,
key: key,
cookie : {
maxAge: maxAge
}
}));
app.use(passport.initialize());
app.use(passport.session());
app.use( express.methodOverride() );
app.use( app.router );
app.use( express.static(application_root) );
app.use(cors());
});
Logging in and auth check:
app.post('/login', cors(corsOptions), passport.authenticate('login', {
successRedirect : successDirect,
failureRedirect : failureDirect
}));
function requireAuth(req, res, next) {
if(req.session.user) {
next();
}
else if (req.cookies.isAuthenticated) {
next();
} else {
res.redirect(loginUrl);
}
}
On login, the session is created. If I send any requests from the server side (localhost:9999/anymethod), then the session is accessed, responses accordingly. If I try to send a request from client side to the same url, then the session is always 'undefined'.
Example:
app.get('/mymethod', cors(corsOptions), requireAuth, function(request, response) {
return response.send("Done");
});
This method works when accessed from server after logging in, but not when accessed from client side (client is established on same server, different domain).
Added to Backbone.js:
initialize: function() {
this.collection.fetch({reset: true, beforeSend: this.beforeFetch});
},
beforeFetch: function(xhr) {
xhr.withCredentials = true;
},...
Edit: The request coming from client doesn't contain any cookies.
How can I access the session created by passport after logging in, sending a request from client?
I guess cors library does it (i haven't used that library). But if it doesn't then in server side
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
next();
});
And in client ajax request
xhrFields: {
withCredentials: true
}

Resources