Skip to content

fix(app-check)!: skip App Check during server rendering by default - #3773

Open
armando-navarro wants to merge 1 commit into
angular:mainfrom
armando-navarro:a43-app-check-server-skip
Open

armando-navarro wants to merge 1 commit into
angular:mainfrom
armando-navarro:a43-app-check-server-skip

Conversation

@armando-navarro

Copy link
Copy Markdown
Collaborator

Fixes #3488
Fixes #3128
Refs #3089

Following docs/app-check.md in a server-rendered app fails the build with ReferenceError: document is not defined. provideAppCheck runs the app's setup function during server rendering, and the reCAPTCHA providers need a browser. This PR skips App Check during server rendering by default, with an opt-in for apps that run it there on purpose.

Important

This is a breaking change, so it needs to merge before 21.0.0 is tagged.

Breaking change

  • During server rendering, AngularFire no longer calls the function passed to provideAppCheck, and inject(AppCheck) returns null there. The browser is unchanged.
  • Apps that run App Check on the server on purpose, with a server-capable provider such as a CustomProvider backed by the Admin SDK, keep the old behavior with one line in their server config:
{ provide: APP_CHECK_ON_SERVER, useValue: true }

Changes

  • appCheckInstanceFactory returns early during server rendering unless APP_CHECK_ON_SERVER is true, and in development mode it warns once that it skipped App Check.
  • APP_CHECK_ON_SERVER is a new export from @angular/fire/app-check, false by default.
  • defaultAppCheckInstanceFactory drops skipped entries before choosing the default instance. ɵgetDefaultInstanceOf reads .app on every entry, so an app calling provideAppCheck twice would otherwise crash on the server.
  • New specs in src/app-check/app-check.spec.ts cover the server default, two provideAppCheck calls on the server, the opt-in, and the browser.
  • The docs change follows in a separate PR.

Verification

On an Angular 21.2 app rendered at build time, using the setup from docs/app-check.md:

  • 21.0.0-rc.1: ng build fails with ReferenceError: document is not defined.
  • This branch: the build succeeds, and AppCheck is null on the server.
  • This branch with APP_CHECK_ON_SERVER and the reCAPTCHA provider: the original error returns, so the opt-in does run App Check on the server.
  • This branch with APP_CHECK_ON_SERVER and a CustomProvider on the server: the build succeeds with a real AppCheck on the server.
  • The warning prints in a development build and not in a production build.
  • npm run test:chrome-headless: 111 passed, 48 skipped. npm run test:node: 331 specs, 0 failures.
  • Each new spec fails when the code it covers is disabled: the server skip, the filter, or the opt-in.

provideAppCheck ran the app's setup function during server rendering,
where the reCAPTCHA providers throw "document is not defined", so
following docs/app-check.md broke every prerender and server render.
The workaround users posted, returning nothing on the server, failed
to compile and left an empty AppCheck object behind.

The setup function now runs only in the browser, unless the server
config provides APP_CHECK_ON_SERVER as true for a server-capable
provider. A skipped server injects AppCheck as null, and development
mode warns once. Firebase's documented route for App Check in server
renders, an appCheckToken passed to initializeServerApp, is unaffected.

BREAKING CHANGE: App Check no longer runs during server rendering
unless APP_CHECK_ON_SERVER is provided as true.

Fixes angular#3488
Fixes angular#3128
Refs angular#3089
@armando-navarro armando-navarro added bump: major comp: app-check App Check (src/app-check). comp: ssr Server-side rendering, hydration, @angular/ssr interop. type: bug Defect: expected behavior doesn't happen. labels Sep 25, 2026

@tyler-reitz tyler-reitz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving. Verified locally rather than by reading: built the branch and ran test:chrome-headless (111 passed, 48 skipped), then disabled each behavior in turn against the built bundle. The server skip, the undefined filter, and the APP_CHECK_ON_SERVER opt-in each take their specs red, so the new coverage is real.

Two non-blocking notes:

  • inject(AppCheck) still types as AppCheck, so SSR code that dereferences it compiles clean and throws at runtime. The dev warning points at docs/app-check.md, so the docs PR is worth landing in the same release.
  • When every provided entry is filtered out, ɵgetDefaultInstanceOf falls through to getImmediate({ optional: true }) on the default app. An App Check instance created outside AngularFire would still resolve on the server, so "injects as null" holds for the documented setup but not universally. Inferred from src/core.ts, not run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bump: major comp: app-check App Check (src/app-check). comp: ssr Server-side rendering, hydration, @angular/ssr interop. type: bug Defect: expected behavior doesn't happen.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Using with Angular 17 SSR -> document is not defined on initializeAppCheck AppCheck Build Error During Prerender for Angular SSR

2 participants