How to setup nonce with NextJS
What is the CSP and Nonce?
Before diving into the implementation, let's understand what CSP and nonce are and why they're important:Content Security Policy (CSP) is a security standard that helps prevent various types of attacks, especially XSS
A nonce is a cryptographically strong random value generated by the server for each HTTP request
Nonces must be unique for every page load and act as temporary security tokens
Example of how nonces work with CSP
// Server generates a nonce
const nonce = generateNonce(); // e.g., "abc123"
// CSP Header
Content-Security-Policy: script-src 'nonce-abc123';
// HTML with nonce
<script nonce="abc123">
console.log("This script will execute");
</script>
<script>
console.log("This script will be blocked");
</script>
SSR Limitation
This implementation is specifically for the Pages Router in Next.js. Nonce values are only accessible server-side. Therefore, any components or features that require the nonce must be configured and rendered on the server side. Client-side components won't have access to the nonce value.
Static Generation Limitation
Since nonce values must be unique per request for security, pages using nonce cannot be statically generated. The page content will be different on each request due to the changing nonce value. You must use server-side rendering methods like getServerSideProps instead of static generation.
1. Create a Nonce Generator
First, let's create a utility function to generate nonces. Create a new fileutils/nonce.ts
. This function uses Node's crypto module to generate a cryptographically secure random value
Nonce generator utility function
// utils/nonce.ts
// Important: This function must be used server-side only as crypto is a Node.js module
export function generateNonce() {
return Buffer.from(crypto.randomBytes(16)).toString('base64');
}
2. Configure Middleware
Create or modify yourmiddleware.ts
file in the root of your project to add CSP headers. The middleware runs before each request and sets up the security headers:
Middleware configuration for CSP and nonce
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { generateNonce } from './utils/nonce';
export function middleware(request: NextRequest) {
// Generate unique nonce for each request
const nonce = generateNonce();
// Important: Store nonce in headers to access it throughout the request lifecycle
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-nonce', nonce);
requestHeaders.set('Content-Security-Policy', cspHeader);
// Important: Define CSP directives with nonce
// Each directive controls different resource types
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}'; // Only allow scripts with matching nonce
style-src 'self' 'nonce-${nonce}'; // Only allow styles with matching nonce
img-src 'self';
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
`.replace(/\s{2,}/g, ' ').trim();
const response = NextResponse.next({
request: {
headers: requestHeaders,
},
});
// Set the CSP header in the response
response.headers.set('Content-Security-Policy', cspHeader);
return response;
}
Creates a unique nonce for each request using cryptographically secure random values
Sets up security directives that control resource loading and incorporates nonce into script and style directives
Handles nonce distribution through headers to make it available throughout the application
Server-Side Access Only
Remember that headers.get('x-nonce') only works in Server Components or server-side code. Client Components cannot access these headers directly.
Next.js Nonce Handling
Next.js automatically extracts the nonce value from the 'Content-Security-Policy' request header and injects it into scripts that require it. This happens server-side during rendering - the nonce value is not accessible to client-side code. Next.js handles this process internally to ensure that all generated scripts are properly nonced.
3. Configure Custom Document
If you're using Pages Router or need more control over the document structure, modify yourpages/_document.tsx
file. This file is crucial for applying the nonce to initial HTML and scripts:
Custom Document configuration with nonce support
// pages/_document.tsx
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
// Important: Get nonce from request headers in getInitialProps
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
const { req } = ctx
// Note: This only works server-side
const nonce = req ? req.headers['x-nonce'] : ''
return { ...initialProps, nonce }
}
render() {
const { nonce } = this.props as any
return (
<Html lang="en">
{/* Important: Apply nonce to Head for all initial styles */}
<Head nonce={nonce}>
<meta charSet="UTF-8" />
<link rel="icon" href="/favicon.ico" />
{/* Example: Inline script must include nonce */}
<script
nonce={nonce}
dangerouslySetInnerHTML={{
__html: `
// Your inline JavaScript here
console.log('Initialized with nonce');
`
}}
/>
</Head>
<body>
<Main />
{/* Important: Apply nonce to NextScript for all Next.js scripts */}
<NextScript nonce={nonce} />
</body>
</Html>
)
}
}
4. Configure App Component
Modify yourpages/_app.tsx
to handle nonce with providers like Chakra UI, Emotion, or other third-party libraries. This setup ensures that all styles and scripts from these libraries are properly nonced:
App component configuration with nonce support
// pages/_app.tsx
import { ChakraProvider } from "@chakra-ui/react";
import createCache from "@emotion/cache";
import { CacheProvider } from "@emotion/react";
import { ReCaptchaProvider } from "next-recaptcha-v3";
function App({ Component, pageProps, nonce }) {
// Important: Create Emotion cache with nonce for styled components
const cache = createCache({
key: "css",
nonce: nonce
});
return (
<CacheProvider value={cache}>
<ChakraProvider>
{/* Important: Pass nonce to third-party providers that support it */}
<ReCaptchaProvider
nonce={nonce}
reCaptchaKey="your-recaptcha-key"
>
<Component {...pageProps} />
</ReCaptchaProvider>
</ChakraProvider>
</CacheProvider>
);
}
// Important: Get nonce from request headers in getInitialProps
App.getInitialProps = async ({ ctx }) => {
const { req } = ctx;
// Note: This only works server-side
const nonce = req ? req.headers["x-nonce"] : "";
return { nonce };
};
export default App;
5. Using with Next.js Script Component
When using Next.js's Script component, you can pass the nonce as a prop. This is particularly useful for loading external scripts safely:Example of using nonce with Next.js Script component
import Script from 'next/script';
import { headers } from 'next/headers';
// Important: This must be a Server Component to access headers
export default function Page() {
// Note: headers() only works in Server Components
const nonce = headers().get('x-nonce');
return (
<div>
{/* Apply nonce to Script component for security */}
<Script
src="/your-script.js"
nonce={nonce}
/>
</div>
);
}
Important Notes
Nonce must be unique per request, cryptographically secure, and have at least 128 bits of entropy
Test CSP headers thoroughly in development and consider using report-only mode initially
Some scripts may need additional CSP directives and external domains added to CSP
Conclusion
This setup provides a strong security foundation for your Next.js application while maintaining functionality. Test thoroughly in your development environment before deploying to production.
Scan Your Website Now
Instantly analyze your website's Content Security Policy. Get actionable insights and improve your security posture in minutes.
Scan Your Website
Enter your website URL to analyze its Content Security Policy configuration.
Get started now by providing your website URL and launch the scan!
Continue Reading
Stay safe, no more unsafe-inline
Learn more about unsafe-inline and how to properly setup your CSP to avoid using it.

How to setup my reporting endpoint?
Learn how to properly setup your reporting endpoint using report-uri & CentralCSP
