# Content Security Policy

> What ngwr needs from a CSP, why a strict `style-src` is usually fine, and the one case where you need a nonce.

Source: https://ngwr.dev/guides/csp

## The short version

The library itself asks for nothing unusual. It contains no `eval`, no `new Function`, no `Worker` and no WebAssembly, and the canvas and WebGL components only call `getContext` — which a CSP does not govern. A client-rendered app that imports ngwr's stylesheet runs under a policy with no escape hatches at all:

```bash
# Client-rendered app that imports ngwr's stylesheet.
Content-Security-Policy:
  default-src 'self';
  script-src  'self';
  style-src   'self';
  img-src     'self' data: blob:;
  font-src    'self';
  base-uri    'self';
  object-src  'none'
```

The part that does the work is the stylesheet import. Twenty-seven entry points — the animation and canvas components, plus `card`, `cascader`, `list`, `lightbox`, `loading-bar`, `virtual-scroll`, `drag-drop` and `breadcrumbs` — declare a `styleUrl` that re-exports the same `styles/_index.scss` you get from `@use`. Angular injects that copy at runtime, and a strict `style-src` blocks the injection. It does not matter, because the identical CSS is already in your linked stylesheet:

```scss
// styles.scss — this is what makes 'self' enough for ngwr.
@use 'ngwr';           // every component, in the linked stylesheet

// …or per component, if you are trimming:
@use 'ngwr/button';
@use 'ngwr/split-text';
```

## If you don't import the stylesheet

Then the runtime injection is the only copy, and it needs a nonce.

Those twenty-seven components render unstyled under `style-src 'self'` if their CSS never reached your stylesheet. Give Angular a nonce and it stamps every style it injects:

```angular-ts
// main.ts — only needed if you do NOT import the stylesheet above.
import { CSP_NONCE } from '@angular/core';

bootstrapApplication(App, {
  providers: [{ provide: CSP_NONCE, useValue: window.__cspNonce }],
});
```

Importing the stylesheet is the better answer: it is one line, it is the documented install path anyway, and it keeps the CSS out of your JavaScript bundle.

## Server-rendered and prerendered apps

The nonce has to come from whatever renders the response — the app root attribute is too late.

Under SSR or prerendering, Angular does not inject component styles from client code. It writes them into the document as `<style ng-app-id="ng">`, so the browser has already parsed — and, under a strict policy, refused — them before your bundle runs. An `ngCspNonce` attribute on the app root cannot retroactively allow them; the nonce must be minted per response by the renderer.

```bash
# Server-rendered or prerendered: Angular writes component CSS into the
# document as <style ng-app-id="ng"> before any client code runs, so a nonce
# has to be produced by whatever renders the response.
Content-Security-Policy:
  style-src 'self' 'nonce-<per-response-random>';

# A statically prerendered site (outputMode: 'static') cannot vary the nonce
# per response. Serve it with hashes, or accept:
Content-Security-Policy:
  style-src 'self' 'unsafe-inline';
```

A statically prerendered site has no per-response step to mint a nonce in, so a nonce there is a fixed string in a cacheable file — which buys nothing. Hashes or `'unsafe-inline'` for `style-src` are the honest options. This is Angular's behaviour, not ngwr's: it applies to your own component styles the same way.

## Directive by directive

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `script-src` | `'self'` is enough. The library contains no `eval`, no `new Function`, no `Worker` and no WebAssembly — verified by sweeping `projects/lib` and by running the built site under a policy with none of the escape hatches. | `directive` | `'self'` |
| `style-src` | `'self'` is enough **if** your app imports ngwr's stylesheet. Every component's CSS then lives in your linked stylesheet. Without that import, see the nonce section below. | `directive` | `'self'` |
| `img-src` | `data:` is needed by `<wr-qr>` and by `<wr-image-cropper>` (both hand you a canvas as a data URL); `blob:` by anything that exports a file, including the table CSV download. | `directive` | `'self' data: blob:` |
| `connect-src` | Only what your own app fetches. The library makes no network calls of its own — `WrI18nHttpLoader` uses whatever URL you configure, and the icon adapters take the icon data as an argument rather than fetching it. | `directive` | `'self'` |
| `'wasm-unsafe-eval'` | Not needed. No entry point compiles WebAssembly. The canvas and WebGL components (`aurora`, `waves`, `splash-cursor`, `click-spark`, `fuzzy-text`, `confetti`) use `getContext` and nothing else, which CSP does not govern. | `not required` | `—` |
| `'unsafe-eval'` | Not needed. Nothing in the library reaches for the string-to-code APIs. | `not required` | `—` |

## This site

```bash
# ngwr.dev itself, for reference. The extra directive is the docs
# highlighter (shiki compiles an Oniguruma WebAssembly module), NOT the library.
Content-Security-Policy:
  script-src 'self' 'wasm-unsafe-eval';
  style-src  'self' 'unsafe-inline';
```

ngwr.dev is prerendered, which is where the `style-src` relaxation comes from, and it highlights code with shiki — whose Oniguruma engine is a WebAssembly module. Neither applies to the library: nothing you install from `ngwr` pulls in a highlighter, and `'wasm-unsafe-eval'` is never needed to run the components. If you add a highlighter to your own app, that dependency's CSP cost is yours to take on.

## See also

- [Theming](https://ngwr.dev/guides/theming) — Where the stylesheet import lives, and what `@use 'ngwr'` pulls in.
- [Tokens](https://ngwr.dev/guides/tokens) — The `--wr-*` custom properties. Setting them is CSSOM, which CSP never blocks.
