I set a cookie with,
router.get("/addCartToCookie", function(req, res) {
let options = {
maxAge: 1000 * 60 * 15,
httpOnly: true,
};
let cartData = {
name: "test cookie",
slug: slugify("test cookie"),
productPictures: "K6B4dzGjN-teal.jpeg",
price: 200,
description: "testing cookies",
quantity: 7,
};
// Set cookie
res.cookie("cartName", cartData, options);
res.send("Cart Added to Cookie");
});
Which perfectly sets a cookie named "cartName". But once I try to get the cookie,
It shows "cartName" is undefined.
Get Cookie Code:
router.get("/getCartFromCookie", function (req, res) {
res.send(req.cookies["cartName"]);
console.log(req.cookies);
});
I tried console logging the cookies but it also shows undefined.
From what I know, the optimized way of handling cookies is by using cookie-parser dependency for express.
$ npm install cookie-parser
Then you could easily fetch your cookies using req.cookies or req.signedCookies property like below:
var express = require('express')
var cookieParser = require('cookie-parser')
var app = express()
app.use(cookieParser())
app.get('/', function (req, res) {
// Cookies that have not been signed
console.log('Cookies: ', req.cookies)
// Cookies that have been signed
console.log('Signed Cookies: ', req.signedCookies)
// Your cart cookie
console.log('Cookies: ', req.cookies.cartName)
})
app.listen(8080);
References:
https://github.com/expressjs/cookie-parser
http://expressjs.com/en/resources/middleware/cookie-parser.html
You don't show all your code, but I assume you're using the cookie-parser middleware to access the cookies directly on the request object. If not, start by adding cookie-parser and go from there.
For your cookie reading issue, be aware that you can't send and read cookies on the same request. You need one request to set the cookie and another to read the cookie.
import express from 'express';
import cookieParser from 'cookie-parser'
import {inspect} from 'util';
const app = express();
const router = express.Router()
router.use(cookieParser())
app.use(router);
const port = 3000
router.get('/setcookie', (req, res) =>{
res.cookie('testCookie', 'magic content');
res.send("set the cookie");
})
router.get('/readCookie', (req, res) =>{
res.send('your cookies: ' + inspect(req.cookies['testCookie']));
console.log(req.cookies);
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
Related
I have req.session variables that I am setting upon login, like so:
req.session.loggedin = true
req.session.firstname = loginDetails.firstName;
what I want to do is pass this information to ALL routes (I have nearly 60, and don't want to go through all of them and add these in manually), and also every route I have calls the front-end using this:
res.render('page.ejs', {data: rows}), so I would ideally want it to pass it to the front-end pages so I can access them there too. Not sure if this is possible, but worth a shot! thx 4 the help in advance!
You can create a middleware function and add variables to an existing express-session.
app.js
const express = require("express");
const session = require("express-session");
// express app
const app = express();
app.use(express.json());
// init example session with express session
app.use(session({ resave: true, secret: "123456", saveUninitialized: true }));
// use a middleware function
app.use((req, res, next) => {
if (!req.session.initialised) {
// init variables you want to set in req.session
req.session.loggedin = true;
req.session.firstname = "john doe";
}
next();
});
// test api endpoint
app.use("/testroute", require("./routes/api/test"));
// run server
const PORT = process.env.PORT || 8000;
app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
Then you can query your variables like req.session.firstname in any other route in the request object. You can also update it from your routes
test.js
// testroute
const router = express.Router();
router.get("/", async (req, res) => {
// get variables from request object
try {
console.log(req.session.firstname);
console.log(req.session.loggedin);
// this would update the session variable if uncommented
// req.session.firstname = "dagobert"
// console.log(req.session.firstname);
res.status(200).json({ message: `Your firstname is ${req.session.firstname}` });
} catch (error) {
res.status(400).json({ message: error.message });
}
});
module.exports = router;
I am developing an angular application which I need to use notifications for example.
I have a user which can add friends and then I can sent a friend request as in facebook and then the other user will be notificate in realtime for example You have one new notification, this user wants to be friends.
If anyone has better idea than socket.io I am free to listen and to learn
The problem it is that I get everytime Cannot GET /socket.io/
Request URL: http://localhost:4200/socket.io/?EIO=3&transport=polling&t=NVvJf99
Request Method: GET
Status Code: 404 Not Found
Remote Address: 127.0.0.1:4200
I can show the list who sent me friend but I need everytime to reload page to see new requests.
I am using socket.io in both frameworks.
Angular I have installed with npm and the same in the mongoDB.
My server.js that is what I use for the requests and responses in frontend.
Server.js
const express = require('express');
const mongoose = require('mongoose');
const http = require('http');
const cors = require('cors');
const routes = require('./src/app/routes/routes');
const path = require('path');
const socketIO = require('socket.io');
const app = express();
const server = http.Server(app);
mongoose.connect('mongodb+srv://vip:admin#test-name-sn4qu.mongodb.net/test?retryWrites=true&w=majority'
, {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false
});
app.use(cors());
const io = socketIO(server);
app.set(io);
app.use(express.json({limit: '50mb'}));
app.use(express.urlencoded({limit: '50mb', extended: true}));
app.use('/images', express.static(path.resolve(process.cwd(), '../images')));
app.use(routes);
mongoose.set('useNewUrlParser', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
app.get("/", (req, res) => {
res.json({ message: "Welcome to application." });
});
const PORT = process.env.PORT || 5000;
server.listen(PORT);
And then in the friendController I use something like this.
function createNewRequest(req, res, next) {
const io = req.app.get('io');
friendService.createNewRequest(req.body)
.then(res.status(200).json({ message: 'Friend added successfully' }),
io.emit('newTaskAdded'))
.catch(err => next(err));
}
And then in the frontend I do have something like this.
And I am having an error which says
Cannot find namespace 'SocketIOClient'. private socket:SocketIOClient.Socket;
import * as io from "socket.io-client";
constructor() {
this.socket = io();
}
ngOnInit(): void {
this.LoadRequestingFriends();
this.socket.on('newTaskAdded', () => {
this.LoadRequestingFriends();
})
}
I have problems with setting up csrf. I hope that someone can point me in the right direction.
I'm using next.js with express.js.
When I refresh the page following happens:
I get a _csurf cookie (dev tools > application > cookies)
a csrf token is logged in my console (-> see last code snipped from context)
when I make a POST request (-> see routes/index.js f.ex. "/aignupQ"), I get the error "Invalid csurf token"; in the request header I can see the _csrf cookie
when I refresh the page and make the POST request again everything works.
I'm really confused by the error and really don't understand what is wrong. Here is some relevant code:
server.js:
require("dotenv").config();
const express = require("express");
const next = require("next");
const bodyParser = require("body-parser");
const cors = require("cors");
const cookieParser = require("cookie-parser");
const routes = require('./routes');
const csrf = require("csurf");
const csrfProtection = csrf({
cookie: true,
});
//next.js configuration
const dev = process.env.NODE_DEV !== "production";
const nextApp = next({ dev });
const port = 3000;
const handle = nextApp.getRequestHandler();
nextApp.prepare().then(() => {
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors());
app.use(cookieParser());
app.use((err, req, res, next) => {
res.status(500).send("Something went wrong!");
});
app.use(csrfProtection);
app.use('/api', routes);
app.get("*", (req, res) => {
return handle(req, res);
});
//start server
app.listen(port, (err) => {
if (err) throw err;
console.log(`listening on port ${port}`);
});
});
routes/index.js:
const express = require('express')
const router = express.Router()
const getCsrfToken = require('../controllers/csrf')
const postSignupQ = require("../controllers/postSignupQ");
const attachUser = require("../middleware/attachUser");
router.get("/csrfToken", getCsrfToken.getCsrfToken);
router.use(attachUser);
router.post("/signupQ", postSignupQ.postSignupQ);
module.exports = router
controllers/csrf.js
const getCsrfToken = (req, res) => {
res.json({ csrfToken: req.csrfToken() });
};
module.exports = { getCsrfToken };
context - here I console.log(csrf):
useEffect(() => {
const getCsrfToken = async() => {
const { data } = await axios.get('api/csrfToken');
console.log("csurf", data);
axios.defaults.headers['X-CSRF-Token'] = data.csrfToken;
};
getCsrfToken();
}, []);
I don't understand why I get the error message, when I make a POST request for the first time and when I refresh the page everything works. What's the problem and how can I solve this?
EDIT
Thanks to Jack Yu the code snippets above are working. Maybe it can help someone else..
EDIT
I also found your api path might be wrong. In your axios is await axios.get('csrfToken'). But, I saw /api/csrfToken in your router. Change it to await axios.get('/api/csrfToken')
Original Answer
In csurf package, when you use csurf({cookie: true}) with cookie mode in middleware at multiple times, it'll break the csrf token in response header with first time post. You could take a look for more detail in CSRF doesn't work on the first post attempt, I've explain the reason in that post. So, there are two solutions you could use.
Solution 1
According to the comments, you use app.use(csruf({cookie: true})) in server.js and router/index.js. Remove the following line in your router/index.js. When you setup csruf in server.js, you could use req.csrfToken() in controllers/csrf.js without setting up csruf again.
const csrf = require("csurf");
const csrfProtection = csrf({
cookie: true,
});
router.use(csrfProtection);
Solution 2
You'll need to use express-session package. Add following code before the csurf. If you have .use(csrf({cookie: true})) in your routes/index.js, remove it.
const session = require('express-session')
// mark1: change it to false
const csrfProtection = csrf({
cookie: false,
});
// blablabla ... other code
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors());
app.use(cookieParser());
// mark2: put here
app.use(session({
name: "test",
secret: "test",
cookie: { maxAge: 3 * 60 * 60 * 1000 },
resave: false,
saveUninitialized: false
}))
// put here
app.use((err, req, res, next) => {
res.status(500).send("Something went wrong!");
});
app.use(csrfProtection);
app.use('/api', routes);
Then change {cookie: true} to {cookie: false} in all csurf setting. When you use session mode, you could use csruf({cookie: false}) many times in middleware.
We need to pass a cookie in header like below:
headerMaps.put("cookie", "_csrf=value; connect.sid=value; csrfToken=value")
There are similar questions out there, but not that directly address why this application of express-session consistently works in Safari but not in chrome.
My server code is below, which only needs to authenticate a single page with a logged out and logged in view. Yesterday, this was working in chrome when served locally and when deployed to Azure or Heroku. Today, with no change made, it wasn't working at all in chrome, both locally or deployed. The home page load but when I click login and am redirected to the Okta login page, this is the error I am getting after logging in when redirected back to my page (e.g. localhost:3000/authorization-code/callback?code=xxxxxxxx&state=xxxxxxxx) after logging in:
Error: did not find expected authorization request details in session, req.session["oidc:https://subdomain.domain.com/oauth2/default"] is undefined
I then tested in Safari where it has consistently worked without issue--both local and hosted. I did just noticed that the hosted version works in Azure again for the moment--again, with no change or redeployment. The local version still does not work.
const http = require('http')
const express = require('express')
const path = require('path')
const app = express()
const fs = require('fs')
require('dotenv').config()
app.use(express.json())
app.use(express.urlencoded({
extended: true
}))
app.use(express.static('express'))
var cors = require('cors')
const OktaJwtVerifier = require('#okta/jwt-verifier')
const session = require('express-session')
const {
ExpressOIDC
} = require('#okta/oidc-middleware')
var getUserInfo = require('./getUserInfo')
// session support is required to use ExpressOIDC
app.use(
session({
secret: 'secretsecret',
resave: true,
saveUninitialized: false,
cookie: {
httpOnly: false,
},
})
)
const oidc = new ExpressOIDC({
issuer: process.env.ISSUER || 'https://[okta hosted custom domain].com/oauth2/default',
client_id: process.env.CLIENT_ID || 'xxxxxxxxxx',
client_secret: process.env.CLIENT_SECRET || 'xxxxxxxxxxxxxxxxxxx',
redirect_uri: process.env.REDIRECT_URI ||
'http://localhost:3000/authorization-code/callback',
appBaseUrl: process.env.APP_BASE_URL || 'http://localhost:3000',
scope: 'openid profile',
})
// ExpressOIDC attaches handlers for the /login and /authorization-code/callback routes
app.use(oidc.router)
app.use(cors())
app.options('*', cors())
app.get('/userinfo', (req, res) => {
console.debug("in user info")
let domain = 'dev'
if (req.isAuthenticated()) {
getUserInfo.userRequest(res, req.userContext, domain)
}
})
app.get('/authStatus', (req, res) => {
console.debug("in auth status")
if (req.isAuthenticated()) {
res.send(req.userContext.userinfo)
}
})
app.post('/forces-logout', oidc.forceLogoutAndRevoke(), (req, res) => {
// Nothing here will execute, after the redirects the user will end up wherever the `routes.logoutCallback.path` specifies (default `/`)
})
// default URL for website
app.get('/', function(req, res) {
res.sendFile(path.join(__dirname + '/express/index.html'))
//__dirname : It will resolve to your project folder.
})
// FAQ Path
app.get('/help', function(req, res) {
res.sendFile(path.join(__dirname + '/express/help.html'))
//__dirname : It will resolve to your project folder.
})
// default URL for website
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname + '/express/index.html'))
//__dirname : It will resolve to your project folder.
})
const port = normalizePort(process.env.PORT || '3000')
const server = http.createServer(app)
server.listen(port)
console.debug('Info site server listening on port ' + port)
function normalizePort(val) {
var port = parseInt(val, 10)
if (isNaN(port)) {
// named pipe
return val
}
if (port >= 0) {
// port number
return port
}
return false
}
I've got the following code on my server.js express application:
var express = require('express');
var fallback = require('express-history-api-fallback');
var compress = require('compression');
var favicon = require('serve-favicon');
var prerenderio = require('prerender-node');
var config = require('getconfig');
var app = express();
app.use(function (req, res, next) {
if (config.environment !== 'local') {
res.cookie('config', JSON.stringify(config), { secure: true });
}
else {
res.cookie('config', JSON.stringify(config));
}
next();
});
app.get('/versioncheck', function(req, res) {
return res.json({ version: config.version });
});
app.use(compress());
app.use(prerenderio.set('prerenderToken', config.prerender_token).set('protocol', 'https'));
app.use(express.static(__dirname, { maxAge: 31536000 }));
app.use(favicon(__dirname + '/favicon.ico'));
app.use(fallback('index.html', { root: __dirname }));
const PORT = process.env.PORT || 1010;
app.listen(PORT, function () {
console.log('Server started on port %s', PORT);
});
The first middleware I'm setting up with express is quite simple: It sends down a cookie to the client with some config information. The issue I'm facing is that this cookie doesn't get sent down to the client upon first request. For all subsequent requests it does work fine. What am I missing?
I had a similar problem some time ago.
At the begin of the first request, the cookie does not exist.
The cookies get sent during the request, not before.
So, at the begin of the second request, the cookie is set (from request 1).