HTTP

Cookie Attribute

Max-Age

Learn how the Max-Age cookie attribute sets expiration in seconds from now. Understand why Max-Age is preferred over Expires for reliable lifetime control.

5 min read beginner Try in Playground

TL;DR: Sets cookie expiration in seconds from now (e.g., Max-Age=3600 for 1 hour) - preferred over Expires because it’s not affected by client clock issues.

What is the Max-Age Attribute?

The Max-Age attribute sets how many seconds a cookie should live, starting from when it’s set. It’s like setting a timer - “delete this cookie in 3600 seconds (1 hour).” Unlike the Expires attribute which uses absolute dates, Max-Age uses relative time, making it immune to client clock issues.

Modern browsers prefer Max-Age over Expires when both are present.

How It Works

Deleted when browser closes:

Set-Cookie: sessionData=temp123
# Expires: When browser session ends
```text

### Persistent Cookie (With Max-Age)

Deleted after specified seconds:

```http
Set-Cookie: rememberMe=true; Max-Age=2592000
# Expires: 30 days from now (2,592,000 seconds)

Time Calculations

Common Durations in Seconds

# 1 minute
Max-Age=60

# 1 hour
Max-Age=3600

# 1 day
Max-Age=86400

# 1 week
Max-Age=604800

# 30 days
Max-Age=2592000

# 1 year
Max-Age=31536000
```text

### Calculation Formula

```text
Seconds = Days × 24 × 60 × 60
```text

## Real-World Examples

### Short-Term Authentication

Session expires in 1 hour:

```http
Set-Cookie: sessionId=abc123; Max-Age=3600; HttpOnly; Secure

Remember Me Login

Keep user logged in for 30 days:

Set-Cookie: rememberToken=xyz789; Max-Age=2592000; HttpOnly; Secure; SameSite=Strict
```text

### Shopping Cart

Keep cart items for 1 week:

```http
Set-Cookie: cartId=cart456; Max-Age=604800; SameSite=Lax

User Preferences

Store theme for 1 year:

Set-Cookie: theme=dark; Max-Age=31536000; Path=/
```text

### Rate Limiting

Temporary block for 15 minutes:

```http
Set-Cookie: rateLimited=true; Max-Age=900; Path=/api

CSRF Token

Short-lived security token (30 minutes):

Set-Cookie: csrfToken=random123; Max-Age=1800; HttpOnly; SameSite=Strict
```text

## Max-Age vs Expires

### Max-Age (Preferred)

```http
Set-Cookie: data=value; Max-Age=86400

Advantages:

  • Not affected by client clock changes
  • Simpler to calculate
  • More reliable
  • Preferred by modern browsers

Expires (Legacy)

Set-Cookie: data=value; Expires=Thu, 16 Jan 2025 10:00:00 GMT
```text

**Disadvantages:**

- Affected by client clock skew
- Requires date formatting
- Can fail if client time is wrong

### Priority Rules

When both are present, Max-Age takes precedence:

```http
Set-Cookie: data=value; Max-Age=3600; Expires=Thu, 16 Jan 2025 10:00:00 GMT
# Browser uses Max-Age (1 hour from now), ignores Expires

Implementation Examples

JavaScript

// Set cookie for 24 hours
const maxAge = 24 * 60 * 60 // 86400 seconds
document.cookie = `userId=123; Max-Age=${maxAge}; Secure`
```javascript

### Express.js

```javascript
// 7 days from now
app.post('/login', (req, res) => {
  res.cookie('sessionId', sessionId, {
    maxAge: 7 * 24 * 60 * 60 * 1000, // Express uses milliseconds!
    httpOnly: true,
    secure: true
  })
})

// Helper function for readability
const days = (n) => n * 24 * 60 * 60 * 1000

res.cookie('rememberMe', 'true', {
  maxAge: days(30), // 30 days
  httpOnly: true
})

Python Flask

from datetime import timedelta

@app.route('/login')
def login():
    response = make_response('Logged in')

    # 1 hour = 3600 seconds
    response.set_cookie(
        'sessionId',
        session_id,
        max_age=3600,
        httponly=True,
        secure=True
    )

    return response
```text

### PHP

```php
// 30 days in seconds
$maxAge = 30 * 24 * 60 * 60; // 2,592,000

setcookie('userId', '123', [
    'max_age' => $maxAge,
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Strict'
]);

Deleting Cookies with Max-Age

Set Max-Age to 0 or negative value:

Set-Cookie: oldCookie=; Max-Age=0; Path=/
Set-Cookie: anotherCookie=; Max-Age=-1; Path=/
```text

**JavaScript:**

```javascript
// Delete cookie immediately
document.cookie = 'sessionId=; Max-Age=0; Path=/'

Express.js:

// Clear cookie
res.clearCookie('sessionId') // Automatically sets Max-Age=0
```text

## Security Considerations

### Appropriate Lifetimes

```http
# Sensitive data: Short lifetime
Set-Cookie: sessionId=secret; Max-Age=3600; HttpOnly; Secure

# Non-sensitive data: Longer lifetime
Set-Cookie: theme=dark; Max-Age=31536000

# Critical operations: Very short lifetime
Set-Cookie: adminToken=xyz; Max-Age=900; HttpOnly; Secure

Session Management

// Different lifetimes for different security levels
const sessionLifetimes = {
  regular: 24 * 60 * 60, // 24 hours
  admin: 2 * 60 * 60, // 2 hours
  banking: 15 * 60, // 15 minutes
  api: 60 * 60 // 1 hour
}

res.cookie('sessionId', sessionId, {
  maxAge: sessionLifetimes.admin * 1000, // Express uses milliseconds
  httpOnly: true,
  secure: true
})
```text

## Best Practices

**1. Use Max-Age instead of Expires:**

```http
✅ Max-Age=86400
❌ Expires=Thu, 16 Jan 2025 10:00:00 GMT

2. Choose appropriate lifetimes:

Session cookies: 1-24 hours
Authentication: 1-30 days
Preferences: 30 days - 1 year
Tracking: Maximum 2 years

3. Use constants for readability:

const HOUR = 60 * 60
const DAY = 24 * HOUR
const WEEK = 7 * DAY

res.cookie('sessionId', sessionId, {
  maxAge: 2 * HOUR * 1000, // 2 hours
  httpOnly: true
})
```javascript

**4. Validate Max-Age values:**

```javascript
function setCookie(name, value, maxAgeSeconds) {
  // Validate reasonable limits
  if (maxAgeSeconds < 0 || maxAgeSeconds > 2 * 365 * 24 * 60 * 60) {
    throw new Error('Invalid Max-Age value')
  }

  res.cookie(name, value, { maxAge: maxAgeSeconds * 1000 })
}

5. Include both for compatibility:

// Maximum compatibility
const maxAgeSeconds = 86400
const expires = new Date(Date.now() + maxAgeSeconds * 1000)

res.cookie('data', value, {
  maxAge: maxAgeSeconds * 1000,
  expires: expires
})
```text

## Common Patterns

### Progressive Expiration

```javascript
// Extend session on activity
app.use((req, res, next) => {
  if (req.cookies.sessionId) {
    // Refresh session cookie
    res.cookie('sessionId', req.cookies.sessionId, {
      maxAge: 24 * 60 * 60 * 1000, // Reset to 24 hours
      httpOnly: true,
      secure: true
    })
  }
  next()
})

Conditional Lifetimes

// Different lifetimes based on user choice
app.post('/login', (req, res) => {
  const maxAge = req.body.rememberMe
    ? 30 * 24 * 60 * 60 * 1000 // 30 days
    : 2 * 60 * 60 * 1000 // 2 hours

  res.cookie('sessionId', sessionId, {
    maxAge: maxAge,
    httpOnly: true,
    secure: true
  })
})
```javascript

### Environment-Based Lifetimes

```javascript
// Shorter lifetimes in development
const maxAge =
  process.env.NODE_ENV === 'production'
    ? 24 * 60 * 60 * 1000 // 24 hours in production
    : 60 * 60 * 1000 // 1 hour in development

res.cookie('sessionId', sessionId, { maxAge })

Troubleshooting

// Problem: Using seconds instead of milliseconds in Express
res.cookie('data', value, { maxAge: 3600 }) // Only 3.6 seconds!

// Solution: Convert to milliseconds
res.cookie('data', value, { maxAge: 3600 * 1000 }) // 1 hour
```text

### Cookie Never Expires

```javascript
// Problem: Negative or zero Max-Age
Set-Cookie: data=value; Max-Age=0  // Deletes immediately

// Solution: Use positive value
Set-Cookie: data=value; Max-Age=86400  // 1 day
  • Expires - Alternative absolute expiration method
  • Secure - HTTPS-only transmission
  • HttpOnly - Prevent JavaScript access
  • SameSite - Cross-site request control

Frequently Asked Questions

What is the Max-Age cookie attribute?

Max-Age specifies cookie lifetime in seconds from when the browser receives it. Max-Age=3600 means the cookie expires in 1 hour.

What is the difference between Max-Age and Expires?

Max-Age uses relative seconds, Expires uses absolute dates. Max-Age is simpler and avoids timezone issues. Max-Age takes precedence if both are set.

What does Max-Age=0 do?

Max-Age=0 or negative values delete the cookie immediately. Use this to log users out or clear cookie data.

What is a session cookie?

Cookies without Max-Age or Expires are session cookies. They are deleted when the browser closes. Use them for temporary data that should not persist.

Keep Learning