# Sessions vs JWT vs Cookies: Understanding Authentication Approaches

Your application needs to know who's accessing it. When a user logs in, you need to remember they're authenticated so they don't have to log in again for every request. There are three main ways to do this: sessions, cookies, and JWT tokens. Each has different tradeoffs.

## What Are Cookies?

Cookies are small pieces of data stored on the client's browser. When you set a cookie, the browser automatically sends it with every request to your server.

Think of cookies like a stamp on your hand at an amusement park. Once you get the stamp, you show it to staff at each ride. The staff don't need to check your ticket every time.

Here's how cookies work:

1.  Server sends a Set-Cookie header in the response
    
2.  Browser stores the cookie
    
3.  Browser automatically includes the cookie in every request back to the server
    

```javascript
// Setting a cookie in Express
res.cookie('username', 'john', { httpOnly: true, maxAge: 3600000 });
res.send('Cookie set');
```

Cookies are just a transport mechanism. By themselves, they don't authenticate anyone. They need to work with either sessions or JWT to be useful.

## What Are Sessions?

A session is server-side storage of user information. When a user logs in, the server creates a session and stores data about that user. The server then sends a session ID to the client, which stores it in a cookie.

**How session-based authentication works:**

1.  User logs in with username and password
    
2.  Server validates credentials and creates a session
    
3.  Server stores session data (like user ID) in memory or a database
    
4.  Server sends session ID in a cookie
    
5.  Browser includes the session cookie in every request
    
6.  Server looks up the session ID to find user information
    

This is stateful authentication. The server maintains state about who's logged in.

```javascript
import express from 'express';
import session from 'express-session';

const app = express();

app.use(session({
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: true,
  cookie: { maxAge: 1000 * 60 * 60 * 24 } // 24 hours
}));

app.post('/login', (req, res) => {
  // Verify user credentials
  const userId = 123;
  
  // Store in session
  req.session.userId = userId;
  res.send('Logged in');
});

app.get('/profile', (req, res) => {
  if (req.session.userId) {
    res.send(`Welcome user ${req.session.userId}`);
  } else {
    res.status(401).send('Not logged in');
  }
});
```

## What is JWT?

JWT stands for JSON Web Token. It's a self-contained token that includes all the information the server needs to authenticate a user. Instead of storing session data on the server, you encode the data into the token itself.

**JWT structure:**

A JWT has three parts separated by dots: `header.payload.signature`

```plaintext
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
```

*   **Header**: Specifies the algorithm used to sign the token
    
*   **Payload**: Contains claims (data) like user ID and username
    
*   **Signature**: Ensures the token hasn't been tampered with
    

Here's how JWT authentication works:

1.  User logs in with username and password
    
2.  Server validates credentials
    
3.  Server creates a JWT with user information
    
4.  Server sends JWT to the client
    
5.  Client stores JWT (usually in localStorage or a cookie)
    
6.  Client sends JWT in the Authorization header with each request
    
7.  Server verifies the signature and extracts user information
    

```javascript
import express from 'express';
import jwt from 'jsonwebtoken';

const app = express();
const SECRET_KEY = 'your-secret-key';

app.post('/login', (req, res) => {
  // Verify user credentials
  const userId = 123;
  const username = 'john';
  
  // Create JWT
  const token = jwt.sign(
    { userId, username },
    SECRET_KEY,
    { expiresIn: '24h' }
  );
  
  res.json({ token });
});

app.get('/profile', (req, res) => {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).send('No token');
  }
  
  try {
    const decoded = jwt.verify(token, SECRET_KEY);
    res.send(`Welcome ${decoded.username}`);
  } catch (error) {
    res.status(401).send('Invalid token');
  }
});
```

## Sessions vs JWT: Key Differences

| Aspect | Sessions | JWT |
| --- | --- | --- |
| **State** | Stateful (server keeps data) | Stateless (data in token) |
| **Storage** | Server (memory/database) | Client (localStorage/cookie) |
| **Scalability** | Harder to scale across multiple servers | Easy to scale (no server state) |
| **Logout** | Easy (delete session) | Harder (token valid until expiry) |
| **Bandwidth** | Small cookie sent | Larger token sent |
| **Mobile** | Works with cookies | Better for APIs |

## When to Use Each

**Use Sessions When:**

*   You're building a traditional web application with server-rendered pages
    
*   You need immediate logout capability
    
*   You're running on a single server or have a shared session store
    
*   You want simpler implementation
    

**Use JWT When:**

*   You're building a mobile app or single-page application
    
*   You have multiple servers that need to authenticate users independently
    
*   You want a stateless architecture
    
*   You're building a public API
    

**Use Cookies When:**

*   You're setting session IDs or tokens
    
*   You need automatic browser handling
    
*   You're building traditional web apps
    

## Common Security Practices

**For Sessions:**

*   Use secure, HttpOnly cookies
    
*   Set appropriate session timeout
    
*   Regenerate session ID on login
    
*   Use HTTPS only
    

**For JWT:**

*   Sign tokens with a strong secret
    
*   Use HTTPS to prevent token interception
    
*   Set reasonable expiry times
    
*   Consider using refresh tokens for longer sessions
    
*   Keep the secret safe
    

## Real-World Example Comparison

Let's say you have a simple blogging platform. Here's how each approach handles a request flow:

**Session-based flow:**

1.  User logs in → Server creates session with user ID
    
2.  User requests profile → Server checks session, recognizes user
    
3.  User logs out → Server deletes session
    

**JWT-based flow:**

1.  User logs in → Server creates token with user ID
    
2.  User requests profile → Token sent with request, server verifies signature
    
3.  User logs out → Client simply deletes token
    

## Key Takeaways

*   Cookies are just a transport mechanism, not authentication by themselves
    
*   Sessions are stateful: server stores user information
    
*   JWT is stateless: user information is stored in the token itself
    
*   Sessions are easier for traditional web apps and immediate logout
    
*   JWT scales better for distributed systems and APIs
    
*   Both can use cookies for transport; the difference is what data is stored where
    

Choose the approach based on your application architecture. Traditional web apps often use sessions, while modern APIs and mobile apps commonly use JWT.
