# Path

> Learn how the Path cookie attribute restricts which URL paths can receive cookies. Understand path matching rules and how to scope cookies to specific routes.

Source: https://howhttpworks.com/cookies/path
Last reviewed: 2026-10-04

> **TL;DR:** Restricts which URL paths receive the cookie (e.g., `Path=/admin` only sends to admin pages) - use to scope cookies to specific app sections and reduce unnecessary cookie transmission.

## What is the Path Attribute?

The **Path** attribute controls which URL paths can receive a cookie. It's like setting delivery instructions for mail - "only deliver to apartments on the 3rd floor." Without this attribute, cookies are sent to all paths on the domain, which can be inefficient and potentially insecure.

This attribute helps scope cookies to specific sections of your application.

## How It Works

### No Path Attribute (Default)

Cookie sent to all paths on the domain:

```http
Set-Cookie: userData=john123
# From: /shop/cart
# Sent to: /, /shop, /shop/cart, /admin, /api, etc.
```

### With Path Attribute

Cookie only sent to matching paths:

```http
Set-Cookie: adminToken=xyz789; Path=/admin
# From: /admin/dashboard
# Sent to: /admin, /admin/dashboard, /admin/users
# Not sent to: /, /shop, /api
```

## Path Matching Rules

### Exact Path and Subdirectories

```http
Set-Cookie: data=value; Path=/shop
```

**Sent to:**

- `/shop` ✅
- `/shop/` ✅
- `/shop/cart` ✅
- `/shop/checkout/payment` ✅

**Not sent to:**

- `/` ❌
- `/api` ❌
- `/shopping` ❌ (different path)
- `/admin` ❌

### Root Path

```http
Set-Cookie: globalData=value; Path=/
```

**Sent to all paths:**

- `/` ✅
- `/shop` ✅
- `/admin` ✅
- `/api/users` ✅

### Specific Subdirectory

```http
Set-Cookie: apiKey=secret; Path=/api/v1
```

**Sent to:**

- `/api/v1` ✅
- `/api/v1/` ✅
- `/api/v1/users` ✅
- `/api/v1/orders/123` ✅

**Not sent to:**

- `/api` ❌
- `/api/v2` ❌
- `/shop` ❌

## Real-World Examples

### Admin Panel Security

Restrict admin cookies to admin paths:

```http
Set-Cookie: adminSession=secure123; Path=/admin; HttpOnly; Secure; Max-Age=3600
```

Admin cookies never sent to public pages, reducing exposure.

### API Authentication

Scope API tokens to API endpoints:

```http
Set-Cookie: apiToken=bearer456; Path=/api; HttpOnly; Secure; SameSite=Strict
```

### Shopping Cart

Keep cart data in shopping section:

```http
Set-Cookie: cartId=cart789; Path=/shop; Max-Age=604800; SameSite=Lax
```

### User Dashboard

Personal data only in user area:

```http
Set-Cookie: userPrefs=theme:dark; Path=/dashboard; Max-Age=2592000
```

### Multi-Tenant Applications

Separate tenant data by path:

```http
Set-Cookie: tenantId=acme; Path=/tenants/acme; Secure
Set-Cookie: tenantId=corp; Path=/tenants/corp; Secure
```

### Development vs Production APIs

```http
# Development API
Set-Cookie: devToken=dev123; Path=/dev/api; Max-Age=86400

# Production API
Set-Cookie: prodToken=prod456; Path=/api; Max-Age=3600
```

## Security Benefits

### Principle of Least Privilege

Only send cookies where needed:

```http
# ❌ Overly broad: Admin token sent everywhere
Set-Cookie: adminToken=secret; HttpOnly; Secure

# ✅ Properly scoped: Admin token only in admin area
Set-Cookie: adminToken=secret; Path=/admin; HttpOnly; Secure
```

### Reduced Attack Surface

```http
# Admin cookie not exposed to public pages
Set-Cookie: adminSession=xyz; Path=/admin; HttpOnly; Secure

# Public pages can't access admin cookies
# Reduces risk if public pages have XSS vulnerabilities
```

### Data Isolation

```http
# Different user types get different cookies
Set-Cookie: customerData=abc; Path=/customer; HttpOnly
Set-Cookie: employeeData=def; Path=/employee; HttpOnly
Set-Cookie: adminData=ghi; Path=/admin; HttpOnly
```

## Implementation Examples

### Express.js

```javascript
// Admin routes
app.use('/admin', (req, res, next) => {
  // Admin-specific cookie
  res.cookie('adminContext', 'true', {
    path: '/admin',
    httpOnly: true,
    secure: true,
    maxAge: 2 * 60 * 60 * 1000 // 2 hours
  })
  next()
})

// API routes
app.use('/api', (req, res, next) => {
  // API-specific cookie
  res.cookie('apiVersion', 'v2', {
    path: '/api',
    maxAge: 24 * 60 * 60 * 1000 // 24 hours
  })
  next()
})

// Shopping cart
app.post('/shop/add-to-cart', (req, res) => {
  res.cookie('cartId', generateCartId(), {
    path: '/shop',
    maxAge: 7 * 24 * 60 * 60 * 1000, // 1 week
    sameSite: 'lax'
  })
})
```

### Python Flask

```python
@app.route('/admin/login', methods=['POST'])
def admin_login():
    session_id = generate_admin_session()

    response = make_response({'success': True})
    response.set_cookie(
        'adminSession',
        session_id,
        path='/admin',
        httponly=True,
        secure=True,
        max_age=7200  # 2 hours
    )

    return response
```

### PHP

```php
// Admin area cookie
if (strpos($_SERVER['REQUEST_URI'], '/admin') === 0) {
    setcookie('adminToken', $token, [
        'expires' => time() + 3600,
        'path' => '/admin',
        'secure' => true,
        'httponly' => true,
        'samesite' => 'Strict'
    ]);
}
```

## Getting Path right

**1. Use specific paths for sensitive cookies:**

```http
✅ Set-Cookie: adminToken=secret; Path=/admin; HttpOnly; Secure
❌ Set-Cookie: adminToken=secret; HttpOnly; Secure
```

**2. Match cookie path to application structure:**

```text
/api/v1     → Path=/api/v1
/admin      → Path=/admin
/user       → Path=/user
/shop       → Path=/shop
```

**3. Use root path sparingly:**

```http
# Only for truly global data
Set-Cookie: siteTheme=dark; Path=/; Max-Age=31536000

# Not for sensitive data
❌ Set-Cookie: sessionId=secret; Path=/
✅ Set-Cookie: sessionId=secret; Path=/app; HttpOnly
```

**4. Consider cookie cleanup:**

```javascript
// Clear cookies from specific paths
app.post('/logout', (req, res) => {
  // Clear admin cookies
  res.clearCookie('adminSession', { path: '/admin' })

  // Clear user cookies
  res.clearCookie('userSession', { path: '/user' })

  // Clear global cookies
  res.clearCookie('globalPrefs', { path: '/' })
})
```

**5. Document path strategy:**

```javascript
// Cookie path strategy:
// /admin/* - Admin-only cookies (sessions, permissions)
// /api/*   - API-specific cookies (tokens, rate limits)
// /shop/*  - Shopping-related cookies (cart, preferences)
// /*       - Global cookies (theme, language)

const COOKIE_PATHS = {
  ADMIN: '/admin',
  API: '/api',
  SHOP: '/shop',
  GLOBAL: '/'
}
```

## Common Patterns

### Hierarchical Permissions

```javascript
// Different access levels with different paths
const setUserCookie = (level, sessionId) => {
  const paths = {
    admin: '/admin',
    manager: '/manager',
    user: '/user',
    public: '/'
  }

  res.cookie('sessionId', sessionId, {
    path: paths[level],
    httpOnly: true,
    secure: true
  })
}
```

### API Versioning

```javascript
// Different cookies for different API versions
app.use('/api/v1', (req, res, next) => {
  res.cookie('apiVersion', 'v1', { path: '/api/v1' })
  next()
})

app.use('/api/v2', (req, res, next) => {
  res.cookie('apiVersion', 'v2', { path: '/api/v2' })
  next()
})
```

### Feature Flags by Section

```javascript
// Different features enabled in different sections
const featureFlags = {
  '/beta': { newUI: true, advancedFeatures: true },
  '/stable': { newUI: false, advancedFeatures: false }
}

app.use('/beta', (req, res, next) => {
  res.cookie('features', JSON.stringify(featureFlags['/beta']), {
    path: '/beta'
  })
  next()
})
```

## Troubleshooting

### Cookie Not Being Sent

```javascript
// Problem: Path doesn't match request URL
Set-Cookie: data=value; Path=/admin
// Request to: /shop/cart (no match)

// Solution: Check path matching
console.log('Request path:', req.path)
console.log('Cookie path:', '/admin')
console.log('Matches:', req.path.startsWith('/admin'))
```

### Cookie Sent to Wrong Paths

```javascript
// Problem: No path restriction
Set-Cookie: adminToken=secret  // Sent everywhere!

// Solution: Add appropriate path
Set-Cookie: adminToken=secret; Path=/admin
```

### Path Case Sensitivity

```javascript
// Problem: Case mismatch
Set-Cookie: data=value; Path=/Admin
// Request to: /admin (lowercase)

// Solution: Use consistent casing (usually lowercase)
Set-Cookie: data=value; Path=/admin
```

## Related Attributes

- [Domain](https://howhttpworks.com/cookies/domain) - Controls domain access
- [Secure](https://howhttpworks.com/cookies/secure) - HTTPS-only transmission
- [HttpOnly](https://howhttpworks.com/cookies/http-only) - Prevent JavaScript access
- [SameSite](https://howhttpworks.com/cookies/same-site) - Cross-site request control
