- Home
- Cookie Attributes
- Max-Age
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.
TL;DR: Sets cookie expiration in seconds from now (e.g.,
Max-Age=3600for 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
Session Cookie (No Max-Age)
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
Cookie Expires Too Soon
// 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
Related Attributes
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.