Passing CSRF token to REACT/FLUX from node
Asked Answered
T

2

11

I'm using nodejs and usually pass down csrf token like the following:

util.js

module.exports.csrf = function csrf(req, res, next){
     res.locals.token = req.csrfToken();
     next();
};

app.js

app.use(csrf());
app.use(util.csrf);

and then in the ejs page I would do

<input type="hidden" name="_csrf" value="<%= token %>">

However, now I'm using flux/react for my front end and need to pass a csrf token for a form submission and not to sure how to do this. There was a similar answer here using jade:

How to implement CSRF protection in Ajax calls using express.js (looking for complete example)?

However, I'm using ejs (with jsx)(or just html) and don't want to use jade

Tanager answered 11/3, 2015 at 20:6 Comment(1)
Echoing Joel, I'd really suggest doing this in a outside of React. I'm fond of how angular's $http service handles this by looking for a session cookie, and including that on every outgoing XHR request.Yand
O
8

I have found the best way to do this in React is to add the csrf token to a store, or pass it to the component context.

You can see how its done by slightly altering the Yahoo Fluxible react-router example.

context.executeAction(setTokenAction, req.csrfToken(), function(){});

This executes a flux action with the csrf token as a parameter. The Yahoo flux architecture serializes the values of the store to the client via:

var exposed = 'window.App=' + serialize(app.dehydrate(context)) + ';';

This gets written out to the page in a script tag, which can then be accessed on in the client-side javascript. It will look something like this:

<script>
window.App = {
  context: {
    dispatcher: {
      stores: {
        ApplicationStore: {
          csrf: "1234abcd",
        }
      }
    }
  }
};
</script>

Here is the Html.jsx component in the Flux example.

If you are not creating an isomorphic application (the React components are run on the sever as well as the client) then I would suggest just to write out a script tag that contains the csrf token.

For Fluxible that value is then rehydrated on the client.

var dehydratedState = window.App; // Sent from the server
var app = require('./app');

app.rehydrate(dehydratedState, function (err, context) {
  ...
});

Leaving you with a populated store on the client without an additional http request. You can then access the csrf token from anywhere by accessing the store.

You can pass it via the context by doing something like this:

var componentContext = context.getComponentContext();
componentContext.csrf = req.csrfToken();

...

var markup = React.renderToString(Component({context: componentContext}))

You can then access it via the component's props.

this.props.context.csrf

If you are using Fluxible and want to pass it via the context I would maybe do it in a plugin, but you get the idea.

Full sever code:

/**
 * Copyright 2014, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
require('babel/register');
var express = require('express');
var favicon = require('serve-favicon');
var serialize = require('serialize-javascript');
var navigateAction = require('./actions/navigate');
var setCsrfTokenAction = require('./actions/setCsrfToken');
var debug = require('debug')('Example');
var React = require('react');
var app = require('./app');
var HtmlComponent = React.createFactory(require('./components/Html.jsx'));
var Router = require('react-router');

var server = express();
server.use(favicon(__dirname + '/../favicon.ico'));
server.use('/public', express.static(__dirname + '/build'));

server.use(function (req, res, next) {
    var context = app.createContext();

    debug('Executing navigate action');
    Router.run(app.getComponent(), req.path, function (Handler, state) {
        context.executeAction(setCsrfTokenAction, req.csrfToken(), function(){});
        context.executeAction(navigateAction, state, function () {
            debug('Exposing context state');
            var exposed = 'window.App=' + serialize(app.dehydrate(context)) + ';';

            debug('Rendering Application component into html');
            var Component = React.createFactory(Handler);
            var html = React.renderToStaticMarkup(HtmlComponent({
                state: exposed,
                markup: React.renderToString(Component({context:context.getComponentContext()}))
            }));

            debug('Sending markup');
            res.send(html);
        });
    });
});

var port = process.env.PORT || 3000;
server.listen(port);
console.log('Listening on port ' + port);
Orchid answered 16/3, 2015 at 3:40 Comment(0)
A
-3

Passing stuff through the template into React is a bit fiddly. It might be better to simply set up an Ajax call for the CSRF token.

This link details how to do it with Django and jQuery, but the concepts should be pretty portable.

Amaro answered 15/3, 2015 at 18:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.