In my app I have a code from official docs, except one difference: I send xsrfToken in response to POST request, not GET.
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
var app = express()
// we need this because "cookie" is true in csrfProtection
app.use(cookieParser())
app.post('/getCsrfToken', /*csrfProtection,*/ function (req, res) {
// check credentials from request.body
// and then
res.render('send', { csrfToken: req.csrfToken() }) //EXCEPTION: csrfToken is not a function
})
app.post('/process', parseForm, csrfProtection, function (req, res) {
res.send('data is being processed')
})
I'm facing the egg-hen problem: if I enable csrfProtection, I cannot get into the endpoint's code without the token, but if I disable it, req.csrfToken becomes undefined.
I need the gerCsrfToken endpoint to be POST, because I don't want to expose password as url parameter.
Question was answered by csurf maintainer, thanks for a quick response!
https://github.com/expressjs/csurf/issues/133
The (tricky) solution is to ignore POST method for this particular endpoint
app.post('/authenticate', csrf({ cookie: true, ignoreMethods: ['POST'] }), function (req, res) {
Related
i am new in node.js. i still couldn't figure out the meaning of configuration on session.
below is example of basic use of session
app.js
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var session = require('express-session');
var cookieParser = require('cookie-parser');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser('cookie'));
app.use(session({
cookie: {
domain: 'localhost',
signed: false,
maxAge:100000,
},
resave: false,
saveUninitialized:false,
secret:'cookie',
rolling:false,
unset:'keep'
}));
app.get('/', function (req, res) {
res.send('this is a router base page!');
});
app.get('/index1.html', function (req, res, next) {
res.sendFile(__dirname + '/index1.html');
next();
});
app.get('/index1.html', function (req, res) {
console.log(req.session.id);
});
app.post('/index1.html', function (req, res) {
if(!req.session.user) req.session.user = req.body;
res.setHeader('Content-Type','text/html');
res.write('session:' + JSON.stringify(req.session));
res.write('expires:'+ JSON.stringify(req.session.cookie.maxAge/1000));
res.end();
});
app.listen(1338);
when i refresh localhost:1338/index.htmlmany times, the req.session.id changes accordingly such as
CboUX1OOMa1veStAmf_9fsEd-ZwNYlW
kWkgsLXsDJcbtEIt9gfSWbg4_ScbG44p
jXLUt0fcCa-wH_jYsU64GznGj1ZNR44G
FjmjRHahDlaC79ngg7k2n1yWni6OHqpt
eLauXn3_SFNxmcWbHMZKAL4d0OVTwzqC
i don't get it why it changes every time even i haven't use post method.
if it changes according to every refreshing web page, what is the difference from req.session.regenerate
req.session.regenerate(function(err){
console.log(req.session.id);
});
but after i wrote username and password in front end form,and submit, then refresh web page again, it won't print session.id any more.
I think i may have some misunderstanding on concept of session.
can anyone help out?
It should give you same token if you introduce time duration setting in session configuration. Something like this
activeDuration: 5 * 60 * 1000
If you are interested for more detail please visit this link https://stormpath.com/blog/everything-you-ever-wanted-to-know-about-node-dot-js-sessions
I'm using express-jwt for athentication, and the following is my code:
api>routes/index.js:
var express = require('express');
var router = express.Router();
var jwt = require('express-jwt');
var auth = jwt({ secret: 'thisIsSecret', requestProperty: 'auth' });
after this inside index.js when i use auth middleware in
router.post('/locations/:locationId/reviews', auth, ctrlReviews.reviewsCreate);
route, when want to post reviews data with post-man, request goes to loading, and no response appear, but if remove auth from route request give response.
I have also checked with
var auth = jwt({
secret: process.env.JWT_SECRET,
userProperty: 'payload'
});
As mentioned in the comments, you're trying to handle valid and invalid tokens. This should be possible with something similar to the below code.
If you use Postman to call this with the following header, then you'll receive 200 OK, with a message of 'OK!'.
Authorization: Bearer validJWT
If you use Postman to call this without a valid JWT then you'll receive 401 Unauthorized with a message of 'invalid token...'.
var jsonwebtoken = require('jsonwebtoken');
var express = require('express');
var app = express();
var jwt = require('express-jwt');
var auth = jwt({ secret: 'thisIsSecret', requestProperty: 'auth'});
// Generate valid JWT
console.log(jsonwebtoken.sign({ foo: 'bar' }, 'thisIsSecret'));
app.post('/locations/:locationId/reviews', auth, function(req, res, next) {
// Log user details set in JWT
console.log(req.auth)
res.send('OK!');
});
// Handle invalid JWT
app.use(function(err, req, res, next) {
if (err.constructor.name === 'UnauthorizedError') {
res.status(401).send('invalid token...');
}
});
app.listen(3000, function() {
console.log('Server running on 3000')
})
req.body is always empty. I'm not sure what I'm doing wrong? I tried adding content-type headers as json but that didn't do anything either. Can someone lead me in the correct direction please? Thank you
EDIT: just for clarification purposes, my Angular frontend hits the backend function successfully, but req.body is empty. If I understand everything correctly, if I'm using the 'body-parser' library, it should be passed in through post through 'req.body'. I'm just not seeing that though and I'm not sure why.
EDIT2: I have the body parser code in my app.js but the backend routing in a index.js file, does that have anything to do with it?
EDIT3: app.js http://pastebin.com/9vNgf0Nd
index.js http://pastebin.com/icLa3e2X
ANGULAR FRONTEND
service.registerAccount = function(account) {
console.log(account); //account = { userName: 'test', password: 'hello' }
return $http({
method: 'POST',
url: '/register',
data: { account: account },
headers: {'Content-Type': 'application/json'}
});
}
BACKEND (app.js)
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
BACKEND (index.js)
var express = require('express');
var router = express.Router();
router.post('/register', function(req, res) {
console.log(req.body);
};
Please remove this line
app.use(bodyParser.urlencoded({ extended: true }))
Also,
app.use(bodyParser.json());
have to be called before app.use('/', routes);
And make sure to add Content-Type: application/json to the request header
What happens if you add the content type?
service.registerAccount = function(account) {
console.log(account); //account = { userName: 'test', password: 'hello' }
return $http({
method: 'POST',
url: '/register',
data: { account: account },
headers: {
'Content-Type': 'application/json'
}
});
}
Try this
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/register', function(req, res) {
console.log(req.body);
});
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
});
and then execute this from prompt:
$ curl localhost:8081/register -v --data "{\"name\":\"test\",\"password\":\"hello\"}" --header "Content-Type: application/json"
this works for me!
There is nothing wrong in the UI code. Not sure what is router so you may try this or post the code for router.
Try this (this works for me) or you can also use your router:
app.post('/register', function (req, res) {
console.log(req.body);
res.send('welcome, ' + req.body.account.username)
});
You are missing:
var app = express();
app.use(router);
If you want to user routers refers to following example:
UPDATE with full code:
var express = require('express');
var router = express.Router();
var app = express();
app.use(router);
router.post('/register', function(req, res) {
console.log(req.body);
};
app.route('/register')
.post(function (req, res) {
console.log(req.body);
res.send('welcome, ' + req.body.account.username)
})
I am trying to use csrf in my NodeJS application.
You can see the code below. When I run this code I am getting "TypeError: req.csrfToken is not a function" error.
I want to create csrf token for all requests and want to check csrf tokens in ajax calls. As I said I can not create csrf token, I am getting error. Also how can I check csrf token in ajax calls?
Can you help me ?
Thanks
Server Side:
var express = require('express');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var csrf = require('csurf');
var bodyParser = require('body-parser');
/*this line commented*/
//var csrfProtection = csrf({ cookie: false });
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
var parseForm = bodyParser.urlencoded({ extended: false });
app.use(cookieParser());
/*this line added*/
app.use(csrf({ cookie: false }));
app.use(session({
genid: function (req) {
return "lkgktktgjknvfndkj-dfgjnkdfkjgn-dfgdfg";
},
name: "mySecret",
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored
secret: 'thisIsASecret'
}));
app.use(express.static(path.join(__dirname, 'public')));
app.use(function (req, res, next) {
res.locals.csrfToken = req.csrfToken();
next();
});
app.get('/', /*csrfProtection,*/ function (req, res) {
res.render('index')
});
app.post('/process', parseForm, /*csrfProtection,*/ function (req, res) {
res.send('data is being processed')
});
Index.jade
meta(name="csrf-token", content="#{csrfToken}")
block content
input(type="hidden" name="_csrf" value="#{csrfToken}")
|Favorite color: <input type="text" name="favoriteColor">
button(type="submit" id="sbmt") Submit
script(src= "/javascripts/jquery-2.2.1.js")
script.
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
var token;
if (!options.crossDomain) {
token = $('meta[name="csrf-token"]').attr('content');
if (token) {
return jqXHR.setRequestHeader('X-CSRF-Token', token);
}
}
});
$("#sbmt").click(function (e) {
e.preventDefault();
$.post(
"/process",
{
//text: text,
_csrf : $('meta[name="csrf-token"]').attr('content')
}, function (data) {
console.log(data);
});
});
You have to add:
app.use(session({ ... });
// Add this after session
app.use(csrfProtection);
You need to add this AFTER the session as stated here:
If you are setting the "cookie" option to a non-false value, then you
must use cookie-parser before this module. Otherwise, you must use a
session middleware before this module. For example: express-session
cookie-session
Calling csrf() returns a function (source). You need to use it in order to have it. What you've missed in the tutorial is:
var csrfProtection = csrf({ cookie: true })
app.get('/form', csrfProtection, function(req, res) {
// pass the csrfToken to the view
res.render('send', { csrfToken: req.csrfToken() })
})
Here, the csrfProtection is actually being called, and it adds csrfToken method to req. In the other example there is:
app.use(csrf({ cookie: true }))
Which means all routes will use the protection and therefore no post without it would be possible.
It depends on your usage - if you want to secure all routes - use it globally (app.use), otherwise use it per request (as in the first example).
If you try using it in your index route you will have it, because you've used it as middleware:
app.get('/', csrfProtection, function (req, res) {
res.render('index')
});
After setting up the Drupal as this guide says: Drupal-passport I created a simple simple node app to test how it works.
It doesn't, I get the InternalOAuthError: Failed to obtain request token error.
Going through the strategy.js, I saw that my callbackURL is logging out undefined not exactly sure why. The callbackURL is set in my Drupal app
Also preforming a curl -i -XPOST http://extranet.local/rest/system/connect/ gives me exactly what I need
Here is my node.js code (keep in mind this is just supposed to test the drupal set up).
var express = require('express');
var passport = require('passport');
var dStrategy = require('passport-drupal').DrupalStrategy;
var passportDrupal = require('passport-drupal');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser')
var session = require('express-session');
var http = require('http');
var app = express();
var server = http.createServer(app);
app.use(cookieParser());
app.use(bodyParser());
app.use(session({ secret: 'SECRET' }));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new dStrategy({
consumerKey: "emDVp7P2LZFLPcN3cNCjLmrjrhQLnNv6",
consumerSecret: "mkbc3UYEuUQLNQRwLWo3B8zEk4ZrErKa",
providerURL: "http://extranet.local",
resourceEndpoint: "rest/system/connect", // <---- optional. Defaults to `rest/system/connect`
callbackURL: 'http://33.33.33.40:8888/auth/drupal/callback'
},
function(token, tokenSecret, profile, done) {
profile.oauth = { token: token, token_secret: tokenSecret };
done(null, profile);
}
));
app.get('/', function(req, res) {
res.writeHead(200);
res.end("This is root");
});
app.get('/auth/drupal',
passport.authenticate('drupal'),
function(req, res) {
// The request will be redirected to the Drupal website for
// authentication, so this function will not be called.
});
app.get('/auth/drupal/callback',
passport.authenticate('drupal', { failureRedirect: '/error' }),
function(req, res) {
// Successful authentication, redirect home.
res.redirect('/signedin');
});
app.get('/error', function(req, res) {
res.writeHead(200);
res.end("Could not sign in");
});
app.get('/signedin', function(req, res) {
res.writeHead(200);
res.end("signed in");
});
server.listen(8888, '33.33.33.40');
Any clues as to why or ideas are greatly appreciated
If you look into the strategy.js code of the library passport-drupal, you will see that the DrupalStrategy constructor does not expect a callbackURL property in the options parameter object and it also does not pass it further into the OAuthStrategy.
This is the code snippet that creates the parameter for the oauth strategy:
// Determine all necessary OAuth options
var oauthOptions = {
requestTokenURL: this._providerURL + '/oauth/request_token',
accessTokenURL: this._providerURL + '/oauth/access_token',
userAuthorizationURL: this._providerURL + '/oauth/authorize',
consumerKey: options.consumerKey,
consumerSecret: options.consumerSecret
};
OAuthStrategy.call(this, oauthOptions, verify);
It should be modified to pass the callbackURL, for example like this:
// Determine all necessary OAuth options
var oauthOptions = {
requestTokenURL: this._providerURL + '/oauth/request_token',
accessTokenURL: this._providerURL + '/oauth/access_token',
userAuthorizationURL: this._providerURL + '/oauth/authorize',
consumerKey: options.consumerKey,
consumerSecret: options.consumerSecret,
callbackURL: options.callbackURL// <==== THIS LINE WAS ADDED
};
OAuthStrategy.call(this, oauthOptions, verify);
I'm not sure that will solve your issue though. But I made a pull request