In the browser
The sign-in form says The email service is unavailable
On /signin, after Send magic link:
The email service is unavailable. Contact support if this continues.
The frontend's terminal shows [auth][error] AggregateError:.
Why: the frontend sends the magic link itself, over SMTP to
EMAIL_SERVER_HOST. In development that is MailDev on port 1025, and it
is not running.
Fix: docker compose up -d maildev from the repository root (or
npm run dev:email in backend/), then send the link again and open
http://localhost:1080.
/backoffice is a 404
Why: frontend/proxy.ts answers every /backoffice/* request with a
404 unless the session belongs to an admin, and a signed-out visitor gets
the same 404. There is no default admin.
Fix: sign in once, then grant yourself admin from backend/:
npm run admin:grant -- [email protected]. See
Make yourself an admin.
An image or script from another site does not load
The browser console shows:
Loading the image 'https://example.com/logo.png' violates the following Content Security Policy directive: "img-src 'self' data: blob: https://images.unsplash.com". The action has been blocked.
Why: buildCsp in frontend/proxy.ts sets a Content Security Policy
on every page, and its img-src lists the hosts images may come from.
Fix for an image: add the host to the img-src line in buildCsp.
A script is a security decision, not a fix. In production script-src
is 'self' 'nonce-...' 'strict-dynamic'. A plain <script src> tag pointing
at another host is blocked:
Loading the script 'http://127.0.0.1:8765/a.js' violates the following Content Security Policy directive: "script-src 'self' 'nonce-xaD5XV2bN0kflx+uNmqTeA==' 'strict-dynamic'". ... The action has been blocked.
Adding its host to script-src changes nothing: the browser reports
Note that 'strict-dynamic' is present, so host-based allowlisting is disabled. What does run is a script inserted by a script that carries the
request's nonce. Next's own runtime scripts carry it, so a script loaded
with next/script (<Script src="..." />) runs, and so does anything
that script loads in turn, because 'strict-dynamic' passes the trust on.
That script then runs with the page's full access: it can read what the
user sees, send requests as the signed-in user and load more code.
Only do it for a script you have chosen to trust, as
Add a page step 6 says. No change to
frontend/proxy.ts is needed, which is why the choice has to be made on
purpose in your own page code.
Related
- Troubleshooting - all entries