Overview
A Content Security Policy (CSP) is a security standard that helps prevent cross-site scripting (XSS), clickjacking, and other code injection attacks. It works by telling the browser exactly which sources of content are trusted. Dynamic’s SDK injects inline<style> elements to render its authentication widgets, including styles within Shadow DOM containers. By default, a strict CSP that disallows inline styles (style-src 'self') will block these styles and break the widget’s appearance.
The cspNonce setting solves this by letting you pass a server-generated nonce to the SDK. Dynamic applies that nonce to every inline <style> and <link> tag it creates, so they pass your CSP without requiring 'unsafe-inline'.
How it works
- Your server generates a unique, unpredictable nonce for each page request
- Your server includes the nonce in both the CSP header and passes it to your application
- You pass the nonce to
DynamicContextProviderviasettings.cspNonce - The SDK automatically applies the nonce to all inline styles it injects, including:
- Shadow DOM reset and widget styles
- Theme styles (
<style>and<link>tags in<head>) - CSS overrides
- Legacy browser compatibility styles
<style> tags with the matching nonce and blocks everything else, keeping your strict CSP intact.
Setup
Generate a nonce on your server
Create a unique, unpredictable nonce for every page request. Use a cryptographically secure random value — never hardcode or reuse a nonce.
Then read the nonce in your layout:
Node.js / Express
Node.js / Express
Next.js (Middleware)
Next.js (Middleware)
middleware.ts
app/layout.tsx
Set the CSP header
Include the nonce in your
style-src or style-src-elem directive. If you use embedded wallets, also include frame-src for the iframe connection.Express.js
Express.js
HTML meta tag (static sites)
HTML meta tag (static sites)
For static sites where you cannot set HTTP headers, you can use a meta tag. Note that this is less secure than a server-set header because the nonce is visible in the HTML source.
NGINX
NGINX
Vercel (vercel.json)
Vercel (vercel.json)
Vercel does not support dynamic nonces in
vercel.json headers. Use Next.js middleware (shown above) or a Vercel Edge Function to generate nonces per request.Full example: Express + React
Here is a complete example showing nonce generation, CSP header configuration, and SDK integration. Server (Express):server.js
App.tsx
CSP directives reference
Here is a recommended baseline CSP for applications using Dynamic:| Directive | Recommended Value | Purpose |
|---|---|---|
default-src | 'self' | Fallback for all resource types |
style-src | 'self' 'nonce-{nonce}' | Allows nonced inline styles and same-origin stylesheets |
style-src-elem | 'self' 'nonce-{nonce}' https: | Allows <style> and <link> elements with the nonce, plus external HTTPS stylesheets |
script-src | 'self' 'nonce-{nonce}' | Allows nonced inline scripts and same-origin scripts |
img-src | 'self' data: blob: | Allows images from same origin, data URIs, and blob URIs |
font-src | 'self' data: | Allows fonts from same origin and data URIs |
connect-src | 'self' https: | Allows API calls to same origin and HTTPS endpoints |
frame-src | 'self' https://app.dynamicauth.com | Required for embedded wallets (iframe connection) |
The
style-src-elem directive (CSP Level 3) provides granular control over <style> elements separately from inline style="" attributes. If your browser support requires it, use style-src instead — it covers both. When a nonce is present in style-src, browsers that support CSP Level 2+ will ignore 'unsafe-inline' for <style> elements, requiring the nonce.Approaches to avoid
| Approach | Why to avoid |
|---|---|
style-src 'unsafe-inline' | Allows all inline styles, defeating the purpose of CSP for style injection attacks |
style-src 'unsafe-hashes' | Only works for static inline styles — breaks when Dynamic injects styles with dynamic content |
| No CSP at all | Leaves your application vulnerable to XSS-based style injection |
Verifying your setup
You can verify that the nonce is correctly applied by inspecting Dynamic’s style elements in your browser’s DevTools:- Open DevTools > Elements
- Find a
.dynamic-shadow-domelement and expand its shadow root - Inspect the
<style>tags inside — each should have anonceattribute matching your CSP
style-src-elem violations from Dynamic’s styles.
Troubleshooting
Styles are broken but no CSP violations in console
Styles are broken but no CSP violations in console
Make sure the nonce value passed to
cspNonce exactly matches the nonce in your CSP header. The CSP header format is 'nonce-{value}' while the cspNonce prop expects just the value (without the nonce- prefix or quotes).CSP violations from third-party libraries
CSP violations from third-party libraries
Other libraries in your application (wallet connectors, toast libraries, etc.) may also inject inline styles without nonce support. These violations are not caused by Dynamic. Check if those libraries offer their own nonce or CSP configuration options.
Nonce not applied in development (Vite / webpack-dev-server)
Nonce not applied in development (Vite / webpack-dev-server)
Dev servers like Vite inject CSS via inline
<style> tags for hot module replacement (HMR). These won’t have your nonce and will trigger CSP violations. This is expected in development — in production builds, CSS is bundled into external files that load via <link> tags (allowed by 'self').Embedded wallet iframe blocked
Embedded wallet iframe blocked
If you’re using embedded wallets, make sure your CSP includes
frame-src 'self' https://app.dynamicauth.com. See the embedded wallet setup guide for details.