Skip to content


Subversion checkout URL

You can clone with
Download ZIP


CSRF fails after the server restart #832

emirotin opened this Issue · 13 comments

3 participants


Using express 3.2.6

Here's my relevant code

csrf_token = (req, res, next) ->
    res.locals.csrf_token = req.session._csrf

    .use('/v1', express.csrf())

Then in my view I have

    div(style="display: none")
        input#csrf-token(type="hidden", value="#{csrf_token}")

And finally I pick this value before every AJAX request.

Appears that after the server restart upon opening the page for the 1st time csrf_token is undefined that makes all my requests fail until I reload the page.


if the route is anything but /v1 then req.session._csrf is going to be undefined


@jonathanong obviously, but the route is /v1/service/inv-view and as I explained the issue only happens the first time I load the page and doesn't happen after reload


'/v1' !== '/v1/service/inv-view'. you want .use('/v1*', express.csrf())


I don't think you're right.

Say for example you wanted to prefix all static files with "/static", you could use the "mounting" feature to support this. Mounted middleware functions are not invoked unless the req.url contains this prefix, at which point it is stripped when the function is invoked. This affects this function only, subsequent middleware will see req.url with "/static" included unless they are mounted as well.

I also have different middleware mounted to prefixes in the same way and they work OK


errr you're right. was thinking about routing


what happens if you just .use(express.csrf())?


The same
(and I need mounting cause I also get POSTs from Facebook who cannot pass the token)

tj commented

you're using the in-memory session store, you'll want to pass something like connect-redis to .session({ store: .. })

@tj tj closed this

But why isn't in-memory store working?
I didin't find in docs that I must use some persistent storage

tj commented

it does work, but when the process goes down all the sessions go with it, the memory store is only really useful for tiny "toy" sites and development


But it doesn't actually

I restart the server
I request the page
I expect the server to generate the token
() I put this token to res.locals and out put it to the page
Then I pick it from the page and put inside of the AJAX request payload
And I see that when the page loads for the first time the token from (
) is undefined

It is obvious that in-memory store is erased when the server restarts, of course. But I don't complain about my old session lost.
I tell you that the new token does not reach the page when it loads for the first time.

tj commented

oh ok I see, hmm, can you reproduce with a small stand-alone app I can check out? or better yet a test for this repo


OK, I have it reproducible
And I assume I also have an explanation

I only want CSRF to be checked on POSTS to specific prefix (like '/api'), so I mount it to that prefix.
Which means the middleware itself isn't called for other requests

Now what happens:
GET '/' -> middleware not called, session._csrf not set, page renders with undefined inside of input
pick _csrf from the input (undefined)
POST '/api/time' -> middleware is called, it sets session._csrf to a newly generated value, then picks _csrf == undefined from my post body and fails

Now when I reload the page the token is already in session._csrf and thus reaches the page

Solution? Creating 2 middleware (initCsrf -> mount for every request, checkCsrf -> mount for particular point).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.