Welcome back, token tamers and security savants! Today, we’re diving into the great JWT storage debate: cookies vs local storage.
JWT storage: the contenders
In the left corner, following the strict rules of RFC 6265, the longtime web staple: HTTP Cookies! And in the right corner, with 10 MiB of pure storage muscle, the modern client-side challenger local storage!
Let’s break down these contenders and see how they stack up in the JWT storage arena.
Local storage: the client-side contender
Local storage is simple; it’s spacious, and it’s always there when you need it. No questions asked.
How it works
```javascript
// Storing a JWT
localStorage.setItem('jwt', 'your.jwt.here');
// Retrieving a JWT
const token = localStorage.getItem('jwt');
```
Pros:
- Capacity: 5 MiB for local storage and 5MiB for session storage per origin.
- More than enough for most JWT needs, but not infinite!
- Ease of use: simple API, easy to access from JavaScript.
- Persistence: stays put even after the browser is closed.
- CSRF proof: local storage is not typically susceptible to CSRF unless something has gone very wrong.
Note: while 5 MiB might sound like “a lot of JWTs,” remember that this is shared with all other local storage data for your domain. Budget wisely!
Cons:
- XSS vulnerability: if an attacker can run JavaScript on your site, your tokens are up for grabs.
- No automatic expiration: tokens stick around until you manually remove them.
Cookies: the HTTP heavyweight
How it works
Cookies are the old guard of web storage. They’ve been around the block, seen some things, and picked up a few tricks along the way.
```javascript
// Storing a JWT in a cookie (server-side)
res.cookie('jwt', 'your.jwt.here', {
httpOnly: true,
secure: true,
sameSite: 'strict'
});
// Retrieving a JWT from a cookie (server-side)
const token = req.cookies.jwt;```
Pros:
- HttpOnly flag: can be made inaccessible to JavaScript, mitigating XSS risks.
- Secure flag: can be set to only transmit over HTTPS.
- Automatic transmission: sent automatically with every HTTP request to your domain.
Cons:
- Size limit: generally limited to 4KB.
- CSRF vulnerability: if not properly protected, can be vulnerable to Cross-Site Request Forgery.
JWT storage security smackdown
When it comes to security, cookies have an edge…but only if you use them correctly.
XSS (Cross-Site Scripting) protection
Local storage:
```javascript
// If this runs, say goodbye to your tokens
const stolenToken = localStorage.getItem('jwt');
sendToEvilServer(stolenToken);
```
Cookies:
```javascript
// With HttpOnly cookies, this returns undefined
const failedAttempt = document.cookie;
console.log("Nice try, hacker:", failedAttempt);
```
HttpOnly cookies are like a bouncer for your tokens, keeping them safe from grabby JavaScript hands.
CSRF (Cross-Site Request Forgery) protection
Cookies are vulnerable to CSRF attacks, but modern defenses exist:
```javascript
// Server-side CSRF token generation
app.use(csrf());
// Client-side CSRF token usage
fetch('/api/data', {
method: 'POST',
headers: {
'CSRF-Token': csrfToken
},
body: JSON.stringify(data)
});
```
Local storage isn’t vulnerable to CSRF, as you have to manually include the token in requests. It’s like having to consciously decide to wear your VIP wristband every time you want to use it.
The verdict
So when it comes to JWT storage, which one should you use? Well, as with many things in tech, it depends.
Use cookies if:
- You’re more worried about XSS than CSRF.
- You’re okay with implementing additional CSRF protections.
- Your JWTs are modest in size.
Use local storage if:
- You’re building a Single Page Application (SPA).
- You’re confident in your XSS protections.
- You need to store larger tokens.
JWT storage best practices, regardless of choice
- Always use HTTPS: whether you’re using cookies or local storage, encrypt that traffic!
- Implement proper CORS policies: don’t let just anyone talk to your server.
- Use short-lived tokens: the shorter the lifespan, the smaller the window for misuse.
- Sanitise and validate user inputs: the best way to prevent most web app attacks is to stop it at the source.
- Security flags and headers: always ensure that you consistently and properly set HTTP security headers and cookie flags.
The hybrid approach
For the “I want it all” types, consider this: use short-lived JWTs in HttpOnly cookies for authentication, and store non-sensitive session data in local storage.
```javascript
// Server-side
res.cookie('jwt', shortLivedToken, { httpOnly: true, secure: true });
// Client-side
localStorage.setItem('userName', 'Bruce Wayne');
```
In conclusion
Whether you choose cookies or local storage, remember that security is an ongoing process. Your choice of JWT storage method is just one piece of the security puzzle.
Stay tuned for our next post, where we’ll explore JWTs in API-centric applications.