diff --git a/browserid/app.js b/browserid/app.js
index b70899b148d12b1429fffce798061616a567d214..5b454608791035eb835bbebffa051ce45aa7db0f 100644
--- a/browserid/app.js
+++ b/browserid/app.js
@@ -37,7 +37,6 @@ const
 fs = require('fs'),
 path = require('path'),
 url = require('url'),
-crypto = require('crypto'),
 wsapi = require('./lib/wsapi.js'),
 httputils = require('./lib/httputils.js'),
 webfinger = require('./lib/webfinger.js'),
@@ -86,15 +85,6 @@ function router(app) {
   // simple redirects (internal for now)
   app.get('/register_iframe', internal_redirector('/dialog/register_iframe.html'));
 
-  // return the CSRF token
-  // IMPORTANT: this should be safe because it's only readable by same-origin code
-  // but we must be careful that this is never a JSON structure that could be hijacked
-  // by a third party
-  app.get('/csrf', function(req, res) {
-    res.write(req.session.csrf);
-    res.end();
-  });
-
   app.get('/', function(req,res) {
     res.render('index.ejs', {title: 'A Better Way to Sign In', fullpage: true});
   });
@@ -116,7 +106,7 @@ function router(app) {
   });
 
   app.get(/^\/manage(\.html)?$/, function(req,res) {
-    res.render('manage.ejs', {title: 'My Account', fullpage: false, csrf: req.session.csrf});
+    res.render('manage.ejs', {title: 'My Account', fullpage: false});
   });
 
   app.get(/^\/tos(\.html)?$/, function(req, res) {
@@ -166,7 +156,7 @@ exports.setup = function(server) {
     secret: COOKIE_SECRET,
     key: COOKIE_KEY,
     cookie: {
-      path: '/',
+      path: '/wsapi',
       httpOnly: true,
       // IMPORTANT: we allow users to go 1 weeks on the same device
       // without entering their password again
@@ -177,32 +167,27 @@ exports.setup = function(server) {
 
   // cookie sessions
   server.use(function(req, resp, next) {
-    // we set this parameter so the connect-cookie-session
-    // sends the cookie even though the local connection is HTTP
-    // (the load balancer does SSL)
-    if (overSSL)
-      req.connection.proxySecure = true;
+    // cookie sessions are only applied to calls to /wsapi
+    // as all other resources can be aggressively cached
+    // by layers higher up based on cache control headers.
+    // the fallout is that all code that interacts with sessions
+    // should be under /wsapi
+    if (/^\/wsapi/.test(req.url)) {
+      // we set this parameter so the connect-cookie-session
+      // sends the cookie even though the local connection is HTTP
+      // (the load balancer does SSL)
+      if (overSSL)
+        req.connection.proxySecure = true;
+
+      return cookieSessionMiddleware(req, resp, next);
 
-    return cookieSessionMiddleware(req, resp, next);
+    } else {
+      return next();
+    }
   });
 
   server.use(express.bodyParser());
 
-  // we make sure that everyone has a session, otherwise we can't do CSRF properly
-  server.use(function(req, resp, next) {
-    if (typeof req.session == 'undefined')
-      req.session = {};
-
-    if (typeof req.session.csrf == 'undefined') {
-      // FIXME: using express-csrf's approach for generating randomness
-      // not awesome, but probably sufficient for now.
-      req.session.csrf = crypto.createHash('md5').update('' + new Date().getTime()).digest('hex');
-      logger.debug("NEW csrf token created: " + req.session.csrf);
-    }
-
-    next();
-  });
-
   // a tweak to get the content type of host-meta correct
   server.use(function(req, resp, next) {
     if (req.url === '/.well-known/host-meta') {
@@ -226,18 +211,6 @@ exports.setup = function(server) {
     next();
   });
 
-  // check CSRF token
-  server.use(function(req, resp, next) {
-    // only on POSTs
-    if (req.method == "POST" && req.body.csrf != req.session.csrf) {
-      // error, problem with CSRF
-      logger.warn("CSRF token mismatch.  got:" + req.body.csrf + " wanted:" + req.session.csrf);
-      httputils.badRequest(resp, "CSRF violation");
-    } else {
-      next();
-    }
-  });
-
   // add middleware to re-write urls if needed
   configuration.performSubstitution(server);
 
diff --git a/browserid/lib/wsapi.js b/browserid/lib/wsapi.js
index ef14ecb6153d2a81ffcfbffde43bf69b79b9f979..d65382a9d1f252506e39c2ed01197dd626c7e734 100644
--- a/browserid/lib/wsapi.js
+++ b/browserid/lib/wsapi.js
@@ -44,6 +44,7 @@ url = require('url'),
 httputils = require('./httputils.js');
 email = require('./email.js'),
 bcrypt = require('bcrypt'),
+crypto = require('crypto'),
 logger = require('../../libs/logging.js').logger;
 
 function checkParams(params) {
@@ -84,6 +85,40 @@ function checkAuthed(req, resp, next) {
 }
 
 function setup(app) {
+  // check CSRF token before routing the request to the proper handler
+  // (iff the request is to /wsapi AND it's a post)
+  app.use(function(req, resp, next) {
+    // only on POSTs to /wsapi
+    if (req.method == "POST" && /^\/wsapi/.test(req.url) && req.body.csrf != req.session.csrf) {
+      // error, problem with CSRF
+      logger.warn("CSRF token mismatch.  got:" + req.body.csrf + " wanted:" + req.session.csrf);
+      httputils.badRequest(resp, "CSRF violation");
+    } else {
+      next();
+    }
+  });
+
+  // return the CSRF token
+  // IMPORTANT: this should be safe because it's only readable by same-origin code
+  // but we must be careful that this is never a JSON structure that could be hijacked
+  // by a third party
+  app.get('/wsapi/csrf', function(req, res) {
+    if (typeof req.session == 'undefined') {
+      req.session = {};
+    }
+
+    if (typeof req.session.csrf == 'undefined') {
+      // FIXME: using express-csrf's approach for generating randomness
+      // not awesome, but probably sufficient for now.
+      req.session.csrf = crypto.createHash('md5').update('' + new Date().getTime()).digest('hex');
+      logger.debug("NEW csrf token created: " + req.session.csrf);
+    }
+
+    res.write(req.session.csrf);
+    res.end();
+  });
+
+
   /* checks to see if an email address is known to the server
    * takes 'email' as a GET argument */
   app.get('/wsapi/have_email', function(req, resp) {
diff --git a/browserid/static/dialog/resources/browserid-network.js b/browserid/static/dialog/resources/browserid-network.js
index 31cc0f8921ab0f4277f79615a47400ad8c83e1cc..aaa3f75412d972379b7636252f8f9bfb19110997 100644
--- a/browserid/static/dialog/resources/browserid-network.js
+++ b/browserid/static/dialog/resources/browserid-network.js
@@ -38,7 +38,7 @@
 var BrowserIDNetwork = (function() {
   var Network = {
     csrf: function(onSuccess) {
-      $.get('/csrf', {}, function(result) {
+      $.get('/wsapi/csrf', {}, function(result) {
         BrowserIDNetwork.csrf_token = result;
         if(onSuccess) {
           onSuccess();