Skip to main content

HTTP Security Headers

Assemble Web applies HTTP security headers to every response via the next.config.js file. The headers differ between development and production environments to balance strict security with a comfortable developer experience.

Configuration Location

All security headers are defined in next.config.js, inside the getSecurityHeaders() function, and applied to every route via the headers() async config key:

async headers() {
return [
{
source: '/(.*)',
headers: getSecurityHeaders(),
}
];
}

Provider Arrays

Before the headers are built, four arrays define the allowed external origins. These are the primary lists to update when a new third-party service is integrated.

ArrayCSP directive it feedsPurpose
providersconnect-srcREST/WebSocket endpoints (APIs, telemetry)
mediaProvidersmedia-srcVideo/audio asset CDNs
scriptSrcItemsscript-src, script-src-elemAllowed external script origins
imageSrcProvidersimg-src (production only)Image proxy / CDN hosts
// next.config.js

const providers = [
'https://*.accedo.tv',
'wss://*.accedo.tv',
'https://*.boltdns.net',
'https://*.brightcovecdn.com',
'https://bam.nr-data.net', // New Relic telemetry
];

const mediaProviders = ['https://*.boltdns.net', 'https://*.brightcovecdn.com'];

const scriptSrcItems = ['https://js-agent.newrelic.com'];

const imageSrcProviders = [
'https://image-proxy.ps.accedo.tv',
'https://cdn.one.accedo.tv',
];

Headers Reference

Development vs. Production

The function checks process.env.NODE_ENV === 'development' and returns a relaxed policy set in development or a strict one in production.

HeaderDevelopmentProduction
Content-Security-PolicyRelaxed (allows unsafe-* for HMR)Strict (no unsafe-*, extra directives)
X-Frame-OptionsDENYDENY
X-Content-Type-Optionsnosniffnosniff
Referrer-Policyno-referrer-when-downgradestrict-origin-when-cross-origin
Permissions-Policy(not set)camera=(), microphone=(), geolocation=()
Strict-Transport-Security(not set)max-age=31536000; includeSubDomains; preload

Content-Security-Policy Directives

DirectiveDevelopment valueProduction value
default-src'self''self'
script-src'self' 'unsafe-eval' 'unsafe-inline' <scriptSrcItems>'self' <scriptSrcItems>
script-src-elem'self' 'unsafe-eval' 'unsafe-inline' <scriptSrcItems>'self' <scriptSrcItems>
style-src'self' 'unsafe-inline''self'
img-src'self' data: https:'self' data: <imageSrcProviders>
font-src'self' data:'self' data:
connect-src'self' <providers>'self' <providers>
media-src'self' blob: <mediaProviders>'self' blob: <mediaProviders>
frame-ancestors'none''none'
base-uri(not set)'self'
form-action(not set)'self'
upgrade-insecure-requests(not set)(set — no value required)
Why unsafe-eval and unsafe-inline in development?

Next.js hot module replacement (HMR) injects inline scripts and uses eval to apply code updates at runtime. These keyword allowances are required for a smooth development experience and are never present in production builds.

Production style-src

In production, style-src is set to 'self' with no 'unsafe-inline'. Any dynamically injected <style> tags (e.g., from third-party libraries) will be blocked by the browser. Audit new dependencies for inline style usage before adding them.

How to Update for a New Project

1. Adding a new API or WebSocket origin

Add the URL to the providers array:

const providers = [
// … existing entries …
'https://api.my-new-service.com',
'wss://realtime.my-new-service.com',
];

2. Adding a new video/audio CDN

Add the CDN origin to mediaProviders:

const mediaProviders = [
// … existing entries …
'https://cdn.my-video-provider.com',
];

3. Adding an external script (e.g., analytics or monitoring)

Add the script origin to scriptSrcItems:

const scriptSrcItems = [
// … existing entries …
'https://cdn.analytics-provider.com',
];

4. Adding an image CDN

Add the hostname to imageSrcProviders and to the images.remotePatterns array in nextConfig so that the Next.js <Image> component can load from it:

const imageSrcProviders = [
// … existing entries …
'https://images.my-cdn.com',
];

// Also update the Next.js images config:
images: {
remotePatterns: [
{ hostname: 'image-proxy.ps.accedo.tv' },
{ hostname: 'cdn.one.accedo.tv' },
{ hostname: 'images.my-cdn.com' }, // ← add here too
],
};
tip

Keep providers, mediaProviders, scriptSrcItems, and imageSrcProviders as specific as possible. Wildcard subdomains (*.example.com) are acceptable when the subdomain space is controlled by a trusted party, but avoid overly broad patterns like https: or *.

Verifying Headers in the Browser

  1. Open DevTools → Network tab.
  2. Reload the page and select the main document request.
  3. Check the Response Headers panel for the headers listed above.