Headers

Security Headers for SaaS Apps — What Changes When Users Log In

Updated April 2026

Reading this? Verify your fix live. Scan your SaaS headers → HeadersFixer

A static marketing site needs three security headers. A SaaS app needs different headers on each type of page — public marketing, authenticated app, and API endpoints all have different security requirements.

Header strategy by route type

HeaderMarketing pagesApp (authenticated)API endpoints
HSTS✅ max-age=31536000✅ same✅ same
X-Frame-OptionsSAMEORIGINDENY (no embedding)N/A
CSPPermissive (analytics, chat)Stricter (nonces)default-src 'none'
Cache-Controlpublic, max-age=3600private, no-storeprivate, no-store
Referrer-Policystrict-origin-when-cross-originsame-originno-referrer

Never cache authenticated responses

# Any response containing user-specific data
Cache-Control: private, no-store

# private = CDN does not cache (browser only)
# no-store = browser does not write to disk cache
# Together = the response exists only in memory during the request

API endpoint headers

# REST API — minimal and correct
Content-Type: application/json
Cache-Control: private, no-store
X-Content-Type-Options: nosniff

# Add CORS if needed (see CORS guides)
Access-Control-Allow-Origin: https://yourapp.com
Access-Control-Allow-Credentials: true

# No CSP needed on JSON API responses — no HTML to execute scripts

CSP for authenticated app routes

# App pages load fewer third-party scripts than marketing pages
# Marketing: GA, Intercom, Hotjar, LinkedIn Pixel...
# App: usually just your own JS, maybe Stripe for billing

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{nonce}' https://js.stripe.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.stripe.com https://api.yourapp.com; frame-src https://js.stripe.com; frame-ancestors 'none'; object-src 'none';

Referrer-Policy tightening for app routes

# Marketing pages — can share referrer with third-party analytics
Referrer-Policy: strict-origin-when-cross-origin

# App pages — users are logged in, do not leak app URLs to third parties
Referrer-Policy: same-origin

# API endpoints — do not send referrer at all
Referrer-Policy: no-referrer

Multi-tenant SaaS — subdomain isolation

# Each customer subdomain: customer1.yourapp.com
# Risk: XSS on one subdomain should not affect others

# Prevent cookie sharing between subdomains:
# Set cookies with domain= set to the exact subdomain, not the parent domain
Set-Cookie: session=abc; Domain=customer1.yourapp.com; HttpOnly; Secure; SameSite=Lax
# NOT: Domain=.yourapp.com (which shares with all subdomains)

Nginx split config by location

server { # Marketing — public caching allowed location / { add_header Cache-Control "public, max-age=3600" always; add_header X-Frame-Options "SAMEORIGIN" always; } # Authenticated app — no caching location /app/ { add_header Cache-Control "private, no-store" always; add_header X-Frame-Options "DENY" always; add_header Referrer-Policy "same-origin" always; } # API — strict no-cache, no iframing context location /api/ { add_header Cache-Control "private, no-store" always; add_header X-Content-Type-Options "nosniff" always; }
}
Scan your SaaS headers → HeadersFixer
Check if your domain is on the HSTS preload list → HSTS Preload Checker