allocatord: relax csrf requirement for non-mutating handlers

With the debug browser integration, it's no longer practical to pass
csrf tokens around for all requests and handlers.  Consequently, we're
now going to only require csrf tokens for mutating requests.  For
non-mutating requests, the redirect through the oauth flow was not
adding much security (Asim and I discussed this a while back).

For now, keep the CSRF token in the email cookie so that it's easily available
for constructing mutating URLs.  It could be its own cookie in theory.

Change-Id: Ia6179947d19a59ffcd484f56db5d34351087ce83
diff --git a/services/allocator/allocatord/assets/assets.go b/services/allocator/allocatord/assets/assets.go
index a2e40c1..cdbde6c 100644
--- a/services/allocator/allocatord/assets/assets.go
+++ b/services/allocator/allocatord/assets/assets.go
@@ -104,7 +104,7 @@
 	return a, nil
 }
 
-var _dashJs = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x94\x57\x6d\x53\xdb\x3e\x12\x7f\xcf\xa7\xd8\xb6\xdc\xd8\xb9\x0b\x26\xa1\x0c\xed\x84\xe9\x74\x20\x70\x25\x73\xe5\xa1\x24\xf4\x5e\x30\x4c\x47\x58\x4a\xac\x56\x96\x52\x49\x06\xd2\x9b\x7c\xf7\x5b\xf9\x51\x26\x86\xff\xfc\x79\x61\xe2\xdd\xfd\xed\xae\xf6\x49\xeb\xdd\x5d\x18\xab\xe5\x4a\xf3\x45\x62\x61\x6f\x30\x3c\x80\x59\xc2\xe0\x3b\x91\x84\xf2\x2c\x85\xa3\xcc\x26\x4a\x9b\x08\x8e\x84\x80\x5c\xc8\x80\x66\x86\xe9\x07\x46\xa3\x2d\x04\xdf\x18\x06\x6a\x0e\x36\xe1\x06\x8c\xca\x74\xcc\x20\x56\x94\x01\xbe\x2e\xd4\x03\xd3\x92\x51\xb8\x5f\x01\x81\xe3\xe9\xc9\x8e\xb1\x2b\xc1\x1c\x4a\xf0\x98\x49\x44\xda\x84\x58\x88\x89\x84\x7b\x06\x73\x95\x49\x0a\x5c\x22\x91\xc1\xd7\xc9\xf8\xf4\x62\x7a\x0a\x73\x2e\x58\xb4\xb5\xf5\x40\x34\x50\x62\x12\xf8\x04\xf3\x4c\xc6\x96\x2b\x19\xf6\xe0\x7f\x5b\x00\xa8\xec\x84\x58\x02\x99\x41\x43\x56\xc1\x82\x49\xa6\x89\x45\x2f\x12\xa2\xad\x89\x50\xc4\x81\xc7\x67\x47\xd7\xb3\x29\xc2\x6f\x91\x00\x39\xd2\xfd\x59\x6e\x05\x1b\x41\xf0\x15\x11\x32\x5e\x41\x98\x9a\x5e\xd0\x2f\x99\x14\xf5\xfe\x87\xad\x1a\x76\xcd\xe1\x14\x89\xa2\x24\xe6\xb4\x75\xbf\x53\xef\xb7\xab\x29\x84\x9a\xfd\xde\xed\x54\xfb\x6d\x69\xda\x2a\x7f\x23\xe1\x35\x75\xe3\xab\x1b\x0c\x38\x59\x30\x08\xff\xd1\xa5\x70\xba\x32\x28\x92\x4b\x5c\xc5\xb6\xad\x3b\x5e\x66\x3b\x99\xe3\xec\x2c\x91\xf5\x9a\x95\x73\x96\x2a\xbd\xaa\x0c\x7d\x39\x7e\xc1\x12\x8a\xe5\x22\xc7\x2b\xcb\x9e\x9d\x23\x65\x69\x69\xeb\xbe\xc5\x34\x31\x71\x16\x86\xbb\xc3\xc1\xde\x7e\xf3\x78\xcd\x99\x13\x6e\x7e\xfd\xa5\x2b\x4e\xe8\x25\x5f\x28\xf2\xfe\xbe\x33\xf8\xbc\x3b\xdc\x2a\x8b\xe7\xe4\xe6\xfa\x68\x36\xb9\xbc\x98\xfe\x98\x5d\xfe\x98\x9e\x8e\x2f\x2f\x4e\x5c\x29\x15\xae\x06\xc3\x24\x18\xc1\xfb\x83\xc1\xa0\x50\x1c\xec\x55\xef\xf0\x4f\xd8\x2b\x69\xfb\x1e\x6d\xbf\xa4\x1d\x78\xb4\x83\x92\x36\xf4\xc1\xc3\x0a\x3d\xa4\x9e\xc6\x0a\xfe\xa1\x45\xc4\xc7\x07\xa4\xaf\x6b\x9f\xf3\x82\xff\xf1\xdf\xc9\xc9\xec\x0c\x5d\xfd\x30\x18\x1c\xb6\x18\x67\xa7\x93\x2f\x67\x33\xe4\xec\xbd\x7f\xc6\x19\x5f\x7e\xbd\xbc\x46\x46\xf0\x6e\x30\xf8\xf8\xfe\xe3\xbf\x83\x5a\x25\xcd\xb0\xb1\xb0\xf3\x26\x72\xca\x62\x25\xa9\x41\x29\xe7\x40\x85\x4f\xb1\x81\x2d\xa3\x17\x24\x65\x0e\x1f\x54\xf4\xd8\xe8\x79\x49\x40\x4a\xd5\xbf\xc0\x9e\xac\x26\xb1\xbd\x22\x1a\x01\x96\x69\x53\x76\x74\x01\xda\xce\xb4\x40\xd0\x76\x84\xff\xc3\xde\x61\x4e\x6f\x1b\x70\x12\xd1\xd2\xa1\xc3\x40\x06\xa5\x48\x69\xcb\xe7\x39\x52\xc5\xd6\xcc\x66\x5a\xb6\x14\xbd\xf9\xf4\x09\x70\xf0\xb0\x39\xc7\x51\xe5\xa4\xd6\x5b\xc5\x58\x99\x32\x9c\x75\xd9\x12\x12\x22\xa9\x40\xf7\x70\x40\x69\x37\x55\xe4\x82\xcb\x45\x1d\x8c\xc8\x3f\x92\x41\xf5\xcb\x93\x92\x33\x56\xd2\x6a\x25\x10\x5a\x1f\x6c\x3b\x0c\xde\x55\x40\x13\xf4\xa2\x38\xe1\x82\x6a\x86\xb3\x2c\x8a\x71\x24\xfe\x0a\x9f\x0d\x37\xf7\x87\x9e\x60\x88\x70\x56\x56\x40\x10\xe4\x9e\x09\x40\xaf\x9c\xbd\xcd\xac\x44\x55\x87\x74\xa4\xab\xab\x92\x6f\xb7\x43\x37\xbd\x7b\x91\xc5\x8c\x84\xbd\xbb\xc3\x12\x9f\x2d\xb1\xc7\x98\x8b\x7d\xe3\xc9\x4d\x4e\x83\x9b\x49\x65\x04\x4f\x14\x55\x86\x76\xb8\x65\x69\x64\x98\x60\x31\x06\x17\x8f\x67\xd5\x62\x21\xd8\x58\x10\x63\xc2\xa0\xa1\x1f\xd6\xd8\xd2\xee\x6b\x62\xeb\x9e\x9f\x93\x2f\x2e\x27\xae\xf5\xf3\xe3\x17\x1e\x1a\x6f\xd4\xd7\x99\xa8\x9c\xf7\x02\x2f\x14\x5e\x69\x72\xb1\x93\x87\x0f\xbd\x33\x89\x7a\xac\x2a\xcb\x55\x5c\x5e\x2e\xa6\xee\x6b\x00\x39\xf2\x0b\xa5\x1e\x3c\xa3\xcd\xc8\x56\x3c\x57\x6a\xa3\xfc\x59\xf8\x7e\x58\x1b\x67\x5a\x2b\xbd\x93\x9a\x05\x1a\x4e\x38\x65\x95\xe1\xed\x88\xfc\x24\x4f\x78\x6c\x4b\xac\xf9\x1c\xc0\xbf\x90\x52\xd4\x6d\xe1\x4e\xaf\x57\xaa\x06\x88\xa8\x92\xac\xa9\x10\x17\x85\xa6\x4a\x9a\x84\x8d\xf3\x60\x14\xec\xc3\x9a\xbb\xf6\xf4\xcc\x09\x17\x5e\xa5\xf9\x2a\x9e\xbb\xea\xc7\xe8\xb9\x9a\x58\xa5\x4b\x81\x8d\xdb\x55\xb4\x2f\xc5\xdc\x3f\xfa\x66\x76\x6f\xca\x7c\x12\xdc\x35\x5e\xcc\xa9\x7f\xbe\xd2\x5e\x71\xb9\x47\xd8\x9f\xa7\x24\x4e\x1a\x7f\x72\x1d\x8d\x53\xf9\x2c\xc2\xfc\x4a\xf6\xe8\xb9\xb9\x50\x0a\xab\x2f\x7a\xe0\x26\x23\x82\xff\x29\x9a\xfa\x48\x33\x92\x1b\x0a\xa9\x8a\xb3\x94\x49\x1b\x2d\x98\x3d\x15\xcc\xfd\x3c\x5e\x4d\x68\xa1\x3b\xe2\xb4\x57\x9f\xc6\xa9\x57\xcb\xbc\xb5\xbd\x22\xaa\x6f\xb2\x02\x90\xbf\xf4\xdb\xbc\x19\xf6\xdd\xd4\x6d\x46\xa3\x56\xfc\xe6\x38\x3f\xa6\xfc\x8f\xbb\xa2\xf6\x1b\xc4\xba\xf9\xf9\xc8\xa9\x4d\x46\xfe\xa4\x6f\x78\x09\x73\xbb\xda\xa8\x35\xed\x1b\xae\x60\xb8\x26\xd1\xb6\xb9\xa5\x32\xdc\x39\x8f\x57\xa6\xc4\x42\x0b\xba\x2c\xe2\xde\xc7\x99\x69\xe3\x06\xed\x57\x6c\x02\x25\x94\x1e\xf9\xb7\x89\xc7\x5e\x77\xa9\x7d\x38\x7a\xe2\x4e\x6b\xca\xe5\x77\x22\x32\x3c\xf1\xc0\xe3\x26\x25\xd7\xd3\xd2\x08\x62\x2e\xdd\xfe\xc7\xf2\x7a\x88\xce\xb9\x9c\x71\x9c\xe9\x78\x77\x0e\x06\x83\x5e\xdf\x87\x90\xa7\x6e\x08\x79\x7a\x09\xb2\xd0\x9c\x0a\xbc\x15\xcc\xe6\x09\x71\x2a\x8c\x60\x67\xd8\x6f\x91\x33\xc9\xed\x86\xac\xdb\x54\x56\x8e\x8a\xd5\x99\x12\x44\xdd\x06\xe7\xe7\xe7\x40\x69\x70\xb7\xee\x3f\x93\x4c\x70\x7f\x6e\x8b\x26\xa3\x34\x05\x12\xf4\x21\x48\xf0\xdf\x26\x22\xe5\x42\x70\x53\x0c\xa1\x2e\xe0\xdd\xba\x05\x68\xe1\xbd\x54\x94\xbf\xd6\x55\x29\xc7\x11\xd5\xe4\x31\xc4\x22\x71\xbb\xf5\x8c\xdc\x8b\x22\x5a\xb7\x45\x11\x97\xbb\xd7\x5d\xbf\x2c\xea\x7c\x93\xea\xf5\xab\xea\x7f\x61\x72\x17\x7b\xb9\x81\x5a\x25\xa8\xfb\x9f\x38\xeb\x61\xae\x55\x9a\x2f\xfd\x0b\xfe\xc0\x24\x16\x22\x97\xcf\x3a\xbf\xe5\x48\xc1\xef\x17\xfb\x9b\xbf\x32\x50\x0b\x45\x77\x77\xf7\x74\xa3\xa1\x74\x90\xda\x88\x50\x3a\x56\x22\x4b\x65\x18\xb8\xd9\x62\xb1\x12\x5c\xb0\x83\x4e\x09\x99\xa5\xf7\x4c\xfb\x7c\x3e\x87\xd2\x9d\x66\xca\x14\x98\x6b\xf5\x68\x4a\x56\x94\x92\x65\x33\x93\x96\xd6\x9f\x92\xe5\x3e\x72\xdb\xca\x52\x5d\xa0\x4b\x1b\xb9\xda\xc4\xbb\x21\x5d\x76\x15\x68\xb9\xc3\xc2\x67\x40\xc9\xbc\xba\x51\xaa\x20\x8d\x6a\x52\x2d\x5f\x5f\xec\xeb\x6a\x66\xad\x81\x09\x5c\x2c\x36\x3c\x0f\x6f\x6b\x17\x30\xab\x83\xbb\x4a\xdc\x5f\xa1\xa8\xad\xb3\x5b\xa7\x89\x63\x03\xd4\x97\x80\x8b\xcd\x9b\x8e\x1d\xaf\x39\x3e\xfa\x89\x03\x36\x78\x2b\xdf\xba\xaf\x45\xfc\x4a\xca\xb8\xc6\x8f\x38\xb7\x66\x71\x89\x87\x96\xf8\x2d\x59\x5e\xc0\x20\x11\xdf\x6c\x0e\x85\x0f\x9e\x53\xdb\x5d\x97\xd0\x8b\xdb\xd8\xe6\x86\x53\xbc\x37\x0b\x0e\xc3\x2f\xd7\x95\x1b\x33\x99\x65\x51\xa3\x6e\x82\xbe\xe8\x07\x22\xc2\x02\xd9\x07\xdc\x7e\x31\x27\x1b\xf5\x5e\xc6\xa8\x0c\x04\x46\x65\x94\x3f\x8b\x05\x7d\xed\x0c\xfe\x3f\x00\x00\xff\xff\xf4\xd9\x7c\x20\x77\x0f\x00\x00")
+var _dashJs = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x94\x57\xdd\x53\xdb\x38\x10\x7f\xe7\xaf\xd8\xb6\xdc\xd8\xb9\x0b\x26\xa1\x0c\xed\x84\xe9\x74\x20\x70\x25\x73\xe5\xa3\x24\xf4\x1e\x18\xa6\x23\x2c\x25\x56\x2b\xcb\xae\x24\x03\xe9\x4d\xfe\xf7\x5b\xf9\x53\x26\x0e\x37\xc7\x83\x89\x77\xf7\xb7\xbb\xda\x2f\xad\x77\x77\x61\x9c\xa4\x4b\xc5\x17\x91\x81\xbd\xc1\xf0\x00\x66\x11\x83\xaf\x44\x12\xca\xb3\x18\x8e\x32\x13\x25\x4a\x07\x70\x24\x04\xe4\x42\x1a\x14\xd3\x4c\x3d\x30\x1a\x6c\x21\xf8\x46\x33\x48\xe6\x60\x22\xae\x41\x27\x99\x0a\x19\x84\x09\x65\x80\xaf\x8b\xe4\x81\x29\xc9\x28\xdc\x2f\x81\xc0\xf1\xf4\x64\x47\x9b\xa5\x60\x16\x25\x78\xc8\x24\x22\x4d\x44\x0c\x84\x44\xc2\x3d\x83\x79\x92\x49\x0a\x5c\x22\x91\xc1\xe7\xc9\xf8\xf4\x62\x7a\x0a\x73\x2e\x58\xb0\xb5\xf5\x40\x14\x50\xa2\x23\xf8\x00\xf3\x4c\x86\x86\x27\xd2\xef\xc1\x3f\x5b\x00\xa8\xec\x84\x18\x02\x99\x46\x43\x26\x81\x05\x93\x4c\x11\x83\x5e\x44\x44\x19\x1d\xa0\x88\x05\x8f\xcf\x8e\xae\x67\x53\x84\xdf\x22\x01\x72\xa4\xfd\x33\xdc\x08\x36\x02\xef\x33\x22\x64\xb8\x04\x3f\xd6\x3d\xaf\x5f\x32\x29\xea\xfd\x8b\x2d\x1b\x76\xcd\xe1\x14\x89\xa2\x24\xe6\xb4\x55\xbf\x53\xef\x97\xab\x29\xf8\x8a\xfd\xdc\xed\x54\xfb\x25\xd5\x6d\x95\x3f\x91\xf0\x92\xba\xf1\xd5\x0d\x06\x9c\x2c\x18\xf8\xbf\x75\x29\x9c\x2e\x35\x8a\xe4\x12\x57\xa1\x69\xeb\x0e\xd3\x6c\x27\xb3\x9c\x9d\x14\x59\x2f\x59\x39\x67\x71\xa2\x96\x95\xa1\x4f\xc7\x1b\x2c\xa1\x58\x2e\x72\xbc\x34\xec\xd9\x39\x62\x16\x97\xb6\xee\x5b\x4c\x1d\x12\x6b\x61\xb8\x3b\x1c\xec\xed\x37\x8f\x97\x9c\x39\xe1\xfa\xc7\x7f\xba\x62\x85\x36\xf9\x42\x91\xf7\xff\x9d\xc1\xe7\xdd\xe1\x56\x59\x3c\x27\x37\xd7\x47\xb3\xc9\xe5\xc5\xf4\xdb\xec\xf2\xdb\xf4\x74\x7c\x79\x71\x62\x4b\xa9\x70\xd5\x1b\x46\xde\x08\xde\x1e\x0c\x06\x85\x62\x6f\xaf\x7a\x87\xdf\x61\xaf\xa4\xed\x3b\xb4\xfd\x92\x76\xe0\xd0\x0e\x4a\xda\xd0\x05\x0f\x2b\xf4\x90\x3a\x1a\x2b\xf8\xbb\x16\x11\x1f\xef\x90\xbe\xaa\x7d\xce\x0b\xfe\xdb\xdf\x93\x93\xd9\x19\xba\xfa\x6e\x30\x38\x6c\x31\xce\x4e\x27\x9f\xce\x66\xc8\xd9\x7b\xfb\x8c\x33\xbe\xfc\x7c\x79\x8d\x0c\xef\xcd\x60\xf0\xfe\xed\xfb\x3f\xbd\x5a\x25\xcd\xb0\xb1\xb0\xf3\x26\x72\xca\xc2\x44\x52\x8d\x52\xd6\x81\x0a\x1f\x63\x03\x1b\x46\x2f\x48\xcc\x2c\xbe\x00\x56\xed\x0a\xec\xc9\x28\x12\x9a\x2b\xa2\x90\x6f\x98\xd2\x65\x03\x17\xd8\xed\x4c\x09\x04\x6d\x07\xf8\xdf\xef\x1d\xe6\xf4\xb6\x3e\x2b\x11\xa4\x16\xed\x7b\xd2\x2b\x45\x14\x33\x99\x92\x2d\xc9\x57\x1f\x3e\x00\x0e\x12\x36\xe7\x38\x7a\xac\xd4\x6a\xab\x18\x13\x53\x86\xb3\x2b\x4b\x21\x22\x92\x0a\xb4\x8f\x03\x47\xd9\x29\x21\x17\x5c\x2e\xea\xc3\x05\xae\xcf\x1a\xd5\xa7\x27\x25\x67\x9c\x48\xa3\x12\x81\xd0\xda\xf3\x6d\xdf\x7b\x53\x01\xb5\xd7\x0b\xc2\x88\x0b\xaa\x18\xce\xa6\x20\xc4\x11\xf7\xc3\x7f\x36\xac\xec\x1f\x7a\x82\x31\xc0\xd9\x57\x01\x41\x90\x7b\x26\x00\xbd\xb2\xf6\xd6\xa3\x1c\x54\x15\xdf\x11\xfe\xae\xca\xbc\xdd\xf6\xed\x34\xee\x05\x06\x43\xee\xf7\xee\x0e\x4b\x7c\x96\x62\xcf\x30\x1b\xdc\xc6\x93\x9b\x9c\x06\x37\x93\xca\x08\x9e\x28\xa8\x0c\xed\x70\xc3\xe2\x40\x33\xc1\x42\x0c\x2e\x1e\xcf\x24\x8b\x85\x60\x63\x41\xb4\xf6\xbd\x86\x7e\x58\x63\x4b\xbb\x2f\x89\xad\x7a\x6e\x4e\x3e\xd9\x9c\xd8\x56\xce\x8f\x5f\x78\xa8\x9d\xd1\x5d\x67\xa2\x72\xde\x09\xbc\x48\xf0\x8a\x92\x8b\x9d\x3c\x7c\xe8\x9d\x8e\x92\xc7\xaa\x74\x6c\x49\xe5\xb5\xa2\xeb\x3e\x05\x90\x23\xb7\x50\xea\x41\x32\x5a\x8f\x6c\xe1\xe9\x61\x6d\x8a\x29\x95\xa8\x9d\x58\x2f\xd0\x4c\xc4\x29\xab\xcc\x6c\x07\xe4\x3b\x79\xc2\x43\x1a\x62\xf4\x47\x0f\xfe\x40\x4a\x51\xa2\x85\xf1\x5e\xaf\x34\x02\x10\xd0\x44\xb2\xa6\x1e\xec\x99\x9b\x9a\x68\xd2\x33\xce\x8f\x5e\xb0\x0f\x6b\xee\xca\xd1\x33\x27\x5c\x38\x75\xe5\xaa\x78\xee\xaa\x1b\x91\xe7\x6a\xc2\x24\x4e\x05\xf6\x61\x57\x89\x6e\x8a\xb0\x7b\xf4\xf5\x5c\xde\x94\xd9\x23\xb8\x29\x6c\xcc\xa0\x7b\xbe\xd2\x5e\x71\x35\x07\xd8\x8d\xa7\x24\x8c\x1a\x7f\x72\x1d\x8d\x53\x36\xa5\x21\x66\x53\xb2\x47\xc7\xcd\x45\x92\x60\xad\x05\x0f\x5c\x67\x44\xf0\x5f\x45\x0b\x1f\x29\x46\x72\x43\x3e\x4d\xc2\x2c\x66\xd2\x04\x0b\x66\x4e\x05\xb3\x3f\x8f\x97\x13\x5a\xe8\x0e\x38\xed\xd5\xa7\xb1\xea\x93\x34\x6f\x64\xa7\x64\xea\x7b\xa8\x00\xe4\x2f\xfd\x36\x6f\x86\x5d\x36\xb5\x7b\xcd\xa8\x15\xbf\x39\x4e\x8b\x29\xff\x65\x2f\x98\xfd\x06\xb1\x6a\x7e\x3e\x72\x6a\xa2\x91\x3b\xa7\x1b\x5e\xc4\xec\xa6\x35\x6a\xcd\xea\x86\x2b\x18\x2e\x39\xb4\x6d\x2e\x4d\x34\xb7\xce\xe3\x85\x27\xb1\xd0\xbc\x2e\x8b\xb8\xb5\x71\xa6\xdb\xb8\x41\xfb\x15\x70\x79\x13\x89\x1a\xb9\x77\x81\xc3\x5e\x75\xa9\x7d\x38\x7a\xe2\x56\x6b\xcc\xe5\x57\x22\x32\x3c\xf1\xc0\xe1\x46\x25\xd7\xd1\xd2\x08\x62\x2e\xed\xf6\xc6\xf2\x7a\x08\xce\xb9\x9c\x71\x9c\xe0\x78\xf3\x0d\x06\x83\x5e\xdf\x85\x90\xa7\x6e\x08\x79\xda\x04\x59\x28\x4e\x05\xde\x01\x7a\xfd\x84\x38\x03\x46\xb0\x33\xec\xb7\xc8\x99\xe4\x66\x4d\xd6\xee\x19\x4b\x4b\xc5\xea\x8c\x09\xa2\x6e\xbd\xf3\xf3\x73\xa0\xd4\xbb\x5b\xf5\x9f\x49\x46\xb8\xfd\xb6\x45\xa3\x51\x1c\x03\xf1\xfa\xe0\x45\xf8\x6f\x1d\x11\x73\x21\xb8\x2e\x46\x4e\x17\xf0\x6e\xd5\x02\xb4\xf0\x4e\x2a\xca\x5f\xab\xaa\x94\xc3\x80\x2a\xf2\xe8\x63\x91\xd8\xcd\x78\x46\xee\x45\x11\xad\xdb\xa2\x88\xcb\xcd\xe9\xae\x5f\x16\x75\xbe\x07\xf5\xfa\x55\xf5\x6f\x98\xd3\xc5\x56\xad\xa1\x56\x09\xc9\xfd\x77\x9c\xec\x30\x57\x49\x9c\xaf\xec\x0b\xfe\xc0\x24\x16\x22\x97\xcf\x3a\xbf\xe5\x48\xc1\xef\x17\xdb\x97\xbb\x01\x50\x03\x45\x77\x77\xf7\x74\xa3\xa1\x74\x90\x9a\x80\x50\x3a\x4e\x44\x16\x4b\xdf\xb3\xb3\xc5\x60\x25\xd8\x60\x7b\x9d\x12\x32\x8b\xef\x99\x72\xf9\x7c\x0e\xa5\x3b\xcd\x94\x29\x30\xd7\xc9\xa3\x2e\x59\x41\x4c\xd2\x66\x26\xa5\xc6\x9d\x92\xe5\xf6\x71\xdb\xca\x52\x5d\xa0\xa9\x09\x6c\x6d\xe2\xdd\x10\xa7\x5d\x05\x5a\x6e\xa0\xf0\x11\x50\x32\xaf\x6e\x94\x2a\x48\xa3\x9a\x54\xcb\xd7\xd7\xf8\xaa\x9a\x59\x2b\x60\x02\xd7\x88\x35\xcf\xfd\xdb\xda\x05\xcc\xea\xe0\xae\x12\x77\x17\x26\x6a\xea\xec\xd6\x69\xe2\xd8\x00\xf5\x25\x60\x63\xf3\xaa\x63\x65\x6b\x8e\x8f\x7e\xe2\x80\xf5\x5e\xcb\xd7\xf6\x5b\x0f\xbf\x71\x32\xae\xf0\x13\xcc\x2e\x55\x5c\xe2\xa1\x25\x7e\x09\x96\xd7\x2d\x48\xc4\x37\x7b\x42\xe1\x83\xe3\xd4\x76\xd7\x25\xb4\x71\xf7\x5a\xdf\x67\x8a\xf7\x66\x9d\x61\xf8\xdd\xb9\xb4\x63\x26\x33\x2c\x68\xd4\x4d\xd0\x17\xf5\x40\x84\x5f\x20\xfb\x80\xbb\x2b\xe6\x64\xad\xde\xcb\x18\x95\x81\xc0\xa8\x8c\xf2\x67\xb1\x5e\xaf\xac\xc1\x7f\x03\x00\x00\xff\xff\x1d\x60\x87\x6b\x35\x0f\x00\x00")
 
 func dashJsBytes() ([]byte, error) {
 	return bindataRead(
diff --git a/services/allocator/allocatord/assets/dash.js b/services/allocator/allocatord/assets/dash.js
index 81ede7d..4a9ea40 100644
--- a/services/allocator/allocatord/assets/dash.js
+++ b/services/allocator/allocatord/assets/dash.js
@@ -50,12 +50,10 @@
 
   var durationInSeconds = 3600;
   var mountedName = '';
-  var csrf = '';
 
   function extractParameters() {
     var $url = $.url();
     mountedName = $url.param('n');
-    csrf = $url.param('csrf');
     return mountedName !== undefined;
   }
 
@@ -77,8 +75,7 @@
     $('#loading-label').show();
     var params = {
       n: mountedName,
-      d: durationInSeconds,
-      csrf: csrf
+      d: durationInSeconds
     };
     $('#error-msg').hide();
     $.ajax('stats?' + $.param(params))
diff --git a/services/allocator/allocatord/cookie.go b/services/allocator/allocatord/cookie.go
index 63d9838..2c160fa 100644
--- a/services/allocator/allocatord/cookie.go
+++ b/services/allocator/allocatord/cookie.go
@@ -15,8 +15,12 @@
 )
 
 type cookieBaker interface {
+	// set creates the cookie with the given name and payload, and also
+	// stores the given csrf token in the cookie.
 	set(w http.ResponseWriter, name, payload, csrfToken string) error
-	get(req *http.Request, name, csrfToken string) (string, error)
+	// get retrieves the payload and csrf token from the cookie.  If the
+	// cookie does not exist, get returns ("", "", nil).
+	get(req *http.Request, name string) (string, string, error)
 }
 
 type signedCookieBaker struct {
@@ -33,30 +37,34 @@
 	// HMAC signs all the above fields and prevents tampering with the
 	// cookie.
 	HMAC []byte `json:"hmac"`
+	// CSRFToken prevents CSRF attacks by ensuring that requests must
+	// contain a csrf token that matches the cookie.
+	CSRFToken string `'json:"csrfToken"`
 }
 
-func (c *signedCookie) computeHMAC(name, csrfToken, signKey string) []byte {
+func (c *signedCookie) computeHMAC(name, signKey string) []byte {
 	mac := hmac.New(sha256.New, []byte(signKey))
 	put := func(data string) {
 		fmt.Fprintf(mac, "%08x%s", len(data), data)
 	}
 	put(name)
-	put(csrfToken)
 	put(c.Payload)
 	put(c.Expiry.String())
+	put(c.CSRFToken)
 	return mac.Sum(nil)
 }
 
-func (c *signedCookie) verifyHMAC(name, csrfToken, signKey string) bool {
-	return hmac.Equal(c.HMAC, c.computeHMAC(name, csrfToken, signKey))
+func (c *signedCookie) verifyHMAC(name, signKey string) bool {
+	return hmac.Equal(c.HMAC, c.computeHMAC(name, signKey))
 }
 
 func (b *signedCookieBaker) packCookie(name, payload, csrfToken string) (string, error) {
 	c := signedCookie{
-		Payload: payload,
-		Expiry:  time.Now().Add(b.validity),
+		Payload:   payload,
+		Expiry:    time.Now().Add(b.validity),
+		CSRFToken: csrfToken,
 	}
-	c.HMAC = c.computeHMAC(name, csrfToken, b.signKey)
+	c.HMAC = c.computeHMAC(name, b.signKey)
 	jsonData, err := json.Marshal(c)
 	if err != nil {
 		return "", err
@@ -64,22 +72,22 @@
 	return base64.URLEncoding.EncodeToString(jsonData), nil
 }
 
-func (b *signedCookieBaker) unpackCookie(name, value, csrfToken string) (string, error) {
+func (b *signedCookieBaker) unpackCookie(name, value string) (string, string, error) {
 	jsonData, err := base64.URLEncoding.DecodeString(value)
 	if err != nil {
-		return "", err
+		return "", "", err
 	}
 	var c signedCookie
 	if err := json.Unmarshal(jsonData, &c); err != nil {
-		return "", err
+		return "", "", err
 	}
 	if time.Now().After(c.Expiry) {
-		return "", fmt.Errorf("cookie expired on %v", c.Expiry)
+		return "", "", fmt.Errorf("cookie expired on %v", c.Expiry)
 	}
-	if !c.verifyHMAC(name, csrfToken, b.signKey) {
-		return "", fmt.Errorf("HMAC mismatching for cookie %v", c)
+	if !c.verifyHMAC(name, b.signKey) {
+		return "", "", fmt.Errorf("HMAC mismatching for cookie %v", c)
 	}
-	return c.Payload, nil
+	return c.Payload, c.CSRFToken, nil
 }
 
 func (b *signedCookieBaker) set(w http.ResponseWriter, name, payload, csrfToken string) error {
@@ -99,13 +107,13 @@
 	return nil
 }
 
-func (b *signedCookieBaker) get(req *http.Request, name, csrfToken string) (string, error) {
+func (b *signedCookieBaker) get(req *http.Request, name string) (string, string, error) {
 	cookie, err := req.Cookie(name)
 	if err == http.ErrNoCookie {
-		return "", nil
+		return "", "", nil
 	}
 	if err != nil {
-		return "", err
+		return "", "", err
 	}
-	return b.unpackCookie(name, cookie.Value, csrfToken)
+	return b.unpackCookie(name, cookie.Value)
 }
diff --git a/services/allocator/allocatord/cookie_test.go b/services/allocator/allocatord/cookie_test.go
index c3a26ab..5d6c7af 100644
--- a/services/allocator/allocatord/cookie_test.go
+++ b/services/allocator/allocatord/cookie_test.go
@@ -18,21 +18,21 @@
 		Payload: "flour, butter, eggs, chocolate",
 		Expiry:  currTime.Add(time.Hour),
 	}
-	hmac := c.computeHMAC("chocolate_chip", "Rumpelstiltskin", "key west")
+	hmac := c.computeHMAC("chocolate_chip", "key west")
 	if want, got := 32, len(hmac); want != got {
 		t.Errorf("Expected %d bytes, got %d instead: %v", want, got, hmac)
 	}
 	c.HMAC = hmac
-	if !c.verifyHMAC("chocolate_chip", "Rumpelstiltskin", "key west") {
+	if !c.verifyHMAC("chocolate_chip", "key west") {
 		t.Errorf("HMAC verification failed for %v | %v", hmac, c)
 	}
 	// Trying a different sign key should not work.
-	if c.verifyHMAC("chocolate_chip", "Rumpelstiltskin", "key east") {
+	if c.verifyHMAC("chocolate_chip", "key east") {
 		t.Errorf("HMAC verification should have failed for %v | %v", hmac, c)
 	}
 	// Fudging the cookie's stored HMAC value should fail validation.
 	c.HMAC[0]++
-	if c.verifyHMAC("chocolate_chip", "Rumpelstiltskin", "key west") {
+	if c.verifyHMAC("chocolate_chip", "key west") {
 		t.Errorf("HMAC verification should have failed for %v | %v", hmac, c)
 	}
 }
@@ -47,27 +47,25 @@
 	if err != nil {
 		t.Fatalf("packCookie failed: %v", err)
 	}
-	p, err := baker.unpackCookie("gingersnap", c, "Rumpelstiltskin")
+	p, csrf, err := baker.unpackCookie("gingersnap", c)
 	if err != nil {
 		t.Fatalf("unpackCookie failed: %v", err)
 	}
 	if want, got := "flour, butter, ginger", p; want != got {
 		t.Errorf("Expected payload %v, got %v instead", want, got)
 	}
-
-	// Using incorrect CSRF token should not work.
-	if _, err := baker.unpackCookie("gingersnap", c, "Wrong CSRF"); err == nil {
-		t.Errorf("unpackCookie should have failed")
+	if want, got := "Rumpelstiltskin", csrf; want != got {
+		t.Errorf("Expected csrf token %v, got %v instead", want, got)
 	}
 
 	// Using bogus string as cookie should not work (and not crash).
-	if _, err := baker.unpackCookie("gingersnap", "blah", "Rumpelstiltskin"); err == nil {
+	if _, _, err := baker.unpackCookie("gingersnap", "blah"); err == nil {
 		t.Errorf("unpackCookie should have failed")
 	}
 
 	// Using wrong sign key should not work.
 	baker.signKey = "key east"
-	if _, err := baker.unpackCookie("gingersnap", c, "Rumpelstiltskin"); err == nil {
+	if _, _, err := baker.unpackCookie("gingersnap", c); err == nil {
 		t.Errorf("unpackCookie should have failed")
 	}
 
@@ -76,7 +74,7 @@
 	if c, err = baker.packCookie("gingersnap", "flour, butter, ginger", "Rumpelstiltskin"); err != nil {
 		t.Fatalf("packCookie failed: %v", err)
 	}
-	if _, err := baker.unpackCookie("gingersnap", c, "Rumpelstiltskin"); err == nil {
+	if _, _, err := baker.unpackCookie("gingersnap", c); err == nil {
 		t.Errorf("unpackCookie should have failed")
 	}
 }
@@ -123,17 +121,18 @@
 	}
 	req.AddCookie(&http.Cookie{Name: "butter_pecan", Value: parts[1][:strings.Index(parts[1], ";")]})
 
-	if p, err := baker.get(req, "butter_pecan", "Rumpelstiltskin"); err != nil {
+	if p, csrf, err := baker.get(req, "butter_pecan"); err != nil {
 		t.Fatalf("get failed: %v", err)
-	} else if want, got := "flour, butter, pecans", p; want != got {
-		t.Errorf("Expected payload %v, got %v instead", want, got)
+	} else {
+		if want, got := "flour, butter, pecans", p; want != got {
+			t.Errorf("Expected payload %v, got %v instead", want, got)
+		}
+		if want, got := "Rumpelstiltskin", csrf; want != got {
+			t.Errorf("Expected csrf token %v, got %v instead", want, got)
+		}
 	}
 
-	if p, err := baker.get(req, "chocolate_mint", "Rumpelstiltskin"); p != "" || err != nil {
-		t.Errorf("get should have returned empty payload for non-existant cookie")
-	}
-
-	if _, err := baker.get(req, "butter_pecan", "Wrong CSRF"); err == nil {
-		t.Errorf("get should have failed with wrong CSRF token")
+	if p, csrf, err := baker.get(req, "chocolate_mint"); p != "" || csrf != "" || err != nil {
+		t.Errorf("get should have returned empty payload and csrf token for non-existant cookie")
 	}
 }
diff --git a/services/allocator/allocatord/handlers.go b/services/allocator/allocatord/handlers.go
index 016e61d..25e5ff6 100644
--- a/services/allocator/allocatord/handlers.go
+++ b/services/allocator/allocatord/handlers.go
@@ -59,8 +59,8 @@
 			CreationTime:     instance.creationTime,
 			BlessingPatterns: instance.blessingNames,
 			DestroyURL:       makeURL(ctx, routeDestroy, params{paramName: instance.mountName, paramCSRF: rs.csrfToken}),
-			DashboardURL:     makeURL(ctx, routeDashboard, params{paramDashboardName: relativeMountName(instance.mountName), paramCSRF: rs.csrfToken}),
-			DebugURL:         makeURL(ctx, routeDebug+"/", params{paramName: instance.mountName, paramCSRF: rs.csrfToken}),
+			DashboardURL:     makeURL(ctx, routeDashboard, params{paramDashboardName: relativeMountName(instance.mountName)}),
+			DebugURL:         makeURL(ctx, routeDebug+"/", params{paramName: instance.mountName}),
 		})
 	}
 	if err := ss.args.assets.executeTemplate(rs.w, homeTmpl, tmplArgs); err != nil {
@@ -75,7 +75,7 @@
 	if err != nil {
 		return fmt.Errorf("create failed: %v", err)
 	}
-	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "created " + name, paramCSRF: rs.csrfToken})
+	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "created " + name})
 	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
 	return nil
 }
@@ -86,7 +86,7 @@
 	if err := destroy(ctx, rs.email, name); err != nil {
 		return fmt.Errorf("destroy failed: %v", err)
 	}
-	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "destroyed " + name, paramCSRF: rs.csrfToken})
+	redirectTo := makeURL(ctx, routeHome, params{paramMessage: "destroyed " + name})
 	http.Redirect(rs.w, rs.r, redirectTo, http.StatusFound)
 	return nil
 }
diff --git a/services/allocator/allocatord/http.go b/services/allocator/allocatord/http.go
index 872a8ce..f86d55f 100644
--- a/services/allocator/allocatord/http.go
+++ b/services/allocator/allocatord/http.go
@@ -233,7 +233,7 @@
 		r:         r,
 	}
 	if err := h.f(h.ss, rs); err != nil {
-		h.ss.args.assets.errorOccurred(ctx, w, r, makeURL(ctx, routeHome, params{paramCSRF: csrfToken}), err)
+		h.ss.args.assets.errorOccurred(ctx, w, r, routeHome, err)
 		ctx.Infof("%s[%s] : error %v", r.Method, r.URL, err)
 		return
 	}
diff --git a/services/allocator/allocatord/oauth.go b/services/allocator/allocatord/oauth.go
index 101aa7c..cd2b933 100644
--- a/services/allocator/allocatord/oauth.go
+++ b/services/allocator/allocatord/oauth.go
@@ -149,7 +149,7 @@
 }
 
 func validateCSRF(ctx *context.T, req *http.Request, baker cookieBaker, csrfToken string) bool {
-	cookieToken, err := baker.get(req, cookieName, csrfToken)
+	cookieToken, cookieCSRFToken, err := baker.get(req, cookieName)
 	if cookieToken == "" && err == nil {
 		err = errors.New("missing cookie")
 	}
@@ -157,16 +157,19 @@
 		ctx.Errorf("Failed to read csrf cookie: %v", err)
 		return false
 	}
-	return csrfCookieValue == cookieToken
+	return cookieToken == csrfCookieValue && cookieCSRFToken == csrfToken
 }
 
 func requireSession(ctx *context.T, oauthCfg *oauth2.Config, baker cookieBaker, w http.ResponseWriter, r *http.Request, mutating bool) (string, string, error) {
-	csrfToken := r.FormValue(paramCSRF)
-	email, err := baker.get(r, cookieName, csrfToken)
+	email, csrfToken, err := baker.get(r, cookieName)
 	switch {
 	case err == nil && email != "" && email != csrfCookieValue:
 		// The user is already logged in.
-		return email, csrfToken, nil
+		if mutating && r.FormValue(paramCSRF) != csrfToken {
+			ctx.Info("Re-authenticating. Bad CSRF token for mutating request.")
+		} else {
+			return email, csrfToken, nil
+		}
 	case err == nil && email == csrfCookieValue:
 		// The user is in the middle of the oauth flow.
 		//
@@ -248,6 +251,5 @@
 		args.assets.badRequest(ctx, w, r, errors.New("no redirect url provided"))
 		return
 	}
-	redirectTo := replaceParam(ctx, state.RedirectURL, paramCSRF, csrfToken)
-	http.Redirect(w, r, redirectTo, http.StatusFound)
+	http.Redirect(w, r, state.RedirectURL, http.StatusFound)
 }