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();
Related
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
I've created a react app that runs on port:3000 and an express app that runs on port:3001.
I am using express-session and connect-mongo to handle user sessions. When I set a user session in /login it was recorded in MongoDB as expected. But when I query for req.session.user later in a different path/route, for example /channels it returns undefined.
This is how my app.js looks
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const {Server} = require("socket.io");
const io = new Server(server);
const port = process.env.PORT || 3001;
const cors = require("cors");
const path = require('path');
const session = require('express-session');
const bodyParser = require('body-parser');
const oneDay = 1000 * 60 * 60 * 24;
const MongoStore = require('connect-mongo');
const md5 = require('md5');
const hash = '=:>q(g,JhR`CK|acXbsDd*pR{/x7?~0o%?9|]AZW[p:VZ(hR%$A5ep ib.&BLo]g';
app.use(session({
secret: hash,
saveUninitialized: false,
resave: false,
store: MongoStore.create({
mongoUrl: 'mongodb://localhost:27017/chat',
ttl: 14 * 24 * 60 * 60 // = 14 days. Default
})
}));
app.use(
cors({
origin: true,
credentials: true,
optionsSuccessStatus: 200
}));
// create application/json parser
const jsonParser = bodyParser.json({limit: '50mb'})
// create application/x-www-form-urlencoded parser
const urlencodedParser = bodyParser.urlencoded({limit: '50mb', extended: false})
app.post('/login', jsonParser, (req, res) => {
db.users.find({email: req.body.email}).toArray().then(user => {
if (user.length < 1) {
res.send({success: false, error: 'NOT_FOUND', message: 'Invalid login info!'});
} else {
user = user[0];
if (user.password === req.body.password) {
db.users.updateOne({"email": user.email}, {$set: {"online": "1"}}).then(ret => {
req.session.user = user.email;
req.session.userdata = user;
res.json(<=user data=>);
});
}
}
})
});
app.post('/channels', async (req, res) => {
if (!req.session.user) {// THIS IS ALWAYS TRUE; EVEN AFTER SUCCESSFUL LOGIN
res.json({logout: true});
return;
}
const user = JSON.parse(req.session.userdata);
const channels = db.channels.find({contacts: {$all: [user._id]}}).toArray().then(channels => {
let allch = {};
channels.map(function (channel) {
channel.id = channel._id.toString();
channel.notif = 0;
allch[channel.id] = channel;
});
res.json(allch);
});
});
When You fetch from front-end for specific route, don't forget to include in options: "credentials: "include" ", like here:
const options = {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(searchInput),
credentials: "include",
};
fetch("http://localhost:4000/sendSearchInput", options)
.then((res) => res.json())
.then((data) => {
console.log(data);
});
Edit:
Note - This should be included in each request from the client that either sets or reads the 'express-session' middleware (req.session.x).
(Not just reads)
I think you will need to call req.session.save() yourself when you want to update the session store with the current data.
I'm new on node js, and the company that i work for needs a proof of concept about postgraphile, the situation is this:
I created a node js mini server that uses postgraphile to access the data on postgres
The mini server works fine and can return data and also can use mutations.
I used keycloak-connect to try to access keycloak to authenticate the token from the request that is sent by postman but there is a problem.
If the token is valid or not it does not matter for the mini server, the only thing that seems to matter is that is a bearer token.
I tried to use other plugins (like keycloak-nodejs-connect, keycloak-verify, etc) but the result is the same, i also changed my code to use the examples in the documentation of those plugins but nothing.
This is my code: (keycloak-config.js file)
var session = require('express-session');
var Keycloak = require('keycloak-connect');
let _keycloak;
var keycloakConfig = {
clientId: 'type credential',
bearerOnly: true,
serverUrl: 'our company server',
realm: 'the test realm',
grantType: "client_credentials",
credentials: {
secret: 'our secret'
}
};
function initKeycloak(){
if(_keycloak){
console.warn("Trying to init Keycloak again!");
return _keycloak;
}
else{
console.log("Initializing Keycloak...");
var memoryStore = new session.MemoryStore();
_keycloak = new Keycloak({store: memoryStore}, keycloakConfig);
return _keycloak;
}
}
function getKeycloak(){
if(!_keycloak){
console.error('Keycloak has not been initialized. Please called init first');
}
return _keycloak;
}
module.exports = {
initKeycloak,
getKeycloak
};
My Index.js file:
const express = require('express')
const bodyParser = require('body-parser')
const postgraphile = require('./postgraphile')
const app = express()
const keycloak = require('../config/keycloak-config').initKeycloak()
var router = express.Router();
app.set( 'trust proxy', true );
app.use(keycloak.middleware());
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(postgraphile);
app.get('/', keycloak.checkSso(), (req, res) => {
res.send('success');
} );
var server = app.listen(8080, () => console.log(`Server running on port ${8080}`));
Also I used this code to get the token and use the keycloak-verify plugin but got nothing:
router.get('/',keycloak.protect(),function(req, res, next) {
var token=req.headers['authorization'];
console.log(token);
try {
let user = keycloak.jwt.verify(token);
console.log(user.isExpired());
} catch (error) {
console.error(error);
}
})
I know that I lack the knowledge because I am a backend (C#) developer, can somebody help me with this?, thanks in advance.
I found the answer to my problem:
const express = require("express");
const request = require("request");
var keycloakConfig = require('../AuthOnly/config/keycloak-config').keycloakConfig;
const postgraphile = require('./postgraphile');
const app = express();
const keycloakHost = keycloakConfig.serverUrl;
const realmName = keycloakConfig.realm;
// check each request for a valid bearer token
app.use((req, res, next) => {
// assumes bearer token is passed as an authorization header
if (req.headers.authorization) {
// configure the request to your keycloak server
const options = {
method: 'GET',
url: `${keycloakHost}/auth/realms/${realmName}/protocol/openid-connect/userinfo`,
headers: {
// add the token you received to the userinfo request, sent to keycloak
Authorization: req.headers.authorization,
},
};
// send a request to the userinfo endpoint on keycloak
request(options, (error, response, body) => {
if (error) throw new Error(error);
// if the request status isn't "OK", the token is invalid
if (response.statusCode !== 200) {
res.status(401).json({
error: `unauthorized`,
});
}
// the token is valid pass request onto your next function
else {
next();
}
});
} else {
// there is no token, don't process request further
res.status(401).json({
error: `unauthorized`,
});
}});
app.use(postgraphile);
app.listen(8080);
I have an Express Server with an endpoint that generates the csrf token for the client,
Now, I tried sending back the token in my axios request as below but I keep getting the usual Forbidden: invalid csrf token error.
Below is my code:
static async attachCSRFTokenToHeaders(headers) {
let csrfTokenRequest = await axios.get(EndPoints.CSRF_TOKEN);
let csRefToken = csrfTokenRequest.data;
headers['X-CSRF-TOKEN'] = csRefToken.csrfToken;
}
static async getRequestHeaders() {
let headers = {};
//Possibly add more headers
await this.attachCSRFTokenToHeaders(headers); //Attach the csrf token to the headers of each request
return headers;
}
static async logInManually(email, password, cb) {
let requestBody = { email, password};
axios.post(EndPoints.SIGN_IN, requestBody, {
headers: await this.getRequestHeaders() //Attach the headers here
}).then((response) => {
cb(HttpSuccessDataHandler.getSuccessResponseData(response), null);
}).catch((e) => {
cb(null, HttpErrorHandler.spitHttpErrorMsg(e));
});
}
But the server still keeps throwing the usual:
ForbiddenError: invalid csrf token
Here is a snippet into my server setup
const csrf = require('csurf');
const cookieParser = require('cookie-parser');
const session = require('express-session');
....
initMiddleWare() {
app.use(express.static('./static'));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser())
app.use(session({
secret: Constants.SESSIONS_SECRET,
resave: false,
saveUninitialized: false
}));
app.use(busboy({
highWaterMark: 2 * 1024 * 1024,
limits: {
fileSize: maxFileSize,
}
}));
app.use(csrf({ cookie: true }))
}
//Then somewhere in my routes, here is the route that provides the csrf token
.....
app.get(Routes.CSRF_TOKEN, function (req, res) {
res.send({ csrfToken: req.csrfToken() });
});
....
Because of csrf({cookie: true}), the CSRF token is bound to a cookie. The axios.post request must contain not only the CSRF token in a header, but also the cookie that was received with the response to the previous axios.get request. Your code sets only the header. Unless axios handles the cookies automatically (like a browser would do), you must include client-side code for handling them as well.
I'm trying to use body-parse version 1.18.3 with express to parse a json post. In app.js I've included it like so
app.js
var express = require('express');
var session = require('express-session');
var bodyParser = require('body-parser');
...
//App setup
var app = express();
// create application/json parser
var jsonParser = bodyParser.json()
app.set('trust proxy', 1) // trust first proxy
// Use the session middleware
app.use(session({ secret: 'secretletters', cookie: {}}))
app.post('/', jsonParser, function (req, res) {
console.log(req.body);
if (req.session.username) {
} else {
}
res.send({'status': 'ok'})
});
and in my script on the frontend send a username back to it
$('.login-btn').click(function() {
let username = $('.username').val();
if (username == '') {
$('.login-error').removeClass('hidden');
return null;
}
//if passed hide error
$('.login-error').addClass('hidden');
var data = {
'username': username
}
$.ajax({
url: "/",
type: "POST",
dataType: 'json',
data: JSON.stringify(data),
success: function(response){
},
error: function(xhr){
},
});
/* End Ajax Call */
});
It send the username successfully, here's a screenshot of the results of the post request from the network tools
the bug is when on console.log(req.body); on app.post I get back and empty {} dict