Unlike most modern web frameworks, Meteor doesn’t make use of cookies. Instead, it uses the relatively new localStorage functionality found in modern browsers. This design decision essentially makes Meteor immune to Cross Site Request Forgery (CSRF) attacks, and opens the door to exciting new authentication features not previously possible with cookies.
CSRF Proof
If Meteor were to use cookies for authentication, it would have to be done during the WebSocket handshake. The handshake is the first and only HTTP request Meteor applications make to the server and is therefore the only place to pass session cookies to the server. However, without some kind of added protection, authentication at this point would expose our Meteor applications to a particularly nasty variant of CSRF dubbed Cross Site WebSocket Hijacking, or CSWSH.
In this scenario, CSWSH could occur if a user authenticated with our application visited a malicious website that attempted to establish a DDP connection to our Meteor application:
var ddp = DDP.connect(‘http://our-application.io’);
ddp.subscribe(...);
ddp.call(...);
DDP.connect
makes a GET
request to our application’s WebSocket endpoint, passing along our session cookie. The GET
request returns with a 101 Switching Protocols
response and the WebSocket is established. WebSocket connections aren’t protected by modern browsers’ same-origin policy, so the browser happily establishes the DDP connection. The malicious site is now free to view, modify, and delete all of your user’s data without their knowledge or consent. Uh oh!
localStorage To The Rescue
Rather than using cookies and implementing complicated countermeasures against CSRF attacks, Meteor opts for a more elegant solution and stores session tokens in localStorage
. localStorage
, unlike cookie data, is accessed via JavaScript and is only accessible by the domain it belongs to. Unlike cookies, they are not sent along with HTTP requests. This means there is no chance of a third party website directly or indirectly accessing and using our users’ session tokens.
Reactive Authentication
Using localStorage
as our authentication mechanism also lets us do cool things like reactive authentication. Imagine a user with your web application loaded on two different tabs. If that user were to log in to your application on one tab, they would instantly be logged in on the other tab. Similarly, logging out of the application in one tab also logs the user out in the second tab. Meteor accomplishes this by listening for storage events and reactively updating the client’s authentication state. These storage events also open the door for more exciting authentication functionality, like sharing authentication state across multiple applications.