question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Modular Auth with compat AuthGuards throws R3InjectorError (NullInjectorError: No provider for InjectionToken angularfire2.app.options!)

See original GitHub issue

Version info

Angular: 12.2.7

Firebase: 9.3.0

AngularFire: 7.0.4

Other (e.g. Ionic/Cordova, Node, browser, operating system):

Node: 12.18.3 Os: macOS Big Sur (11.2.3)

How to reproduce these conditions

Steps to set up and reproduce

  1. Create an app, using the new, modular providers
// app.module.ts
import { provideFirebaseApp, initializeApp, getApp } from '@angular/fire/app';
import {
  initializeAuth,
  provideAuth,
  browserPopupRedirectResolver,
  indexedDBLocalPersistence,
  connectAuthEmulator,
} from '@angular/fire/auth';
...
@NgModule({
...
imports: [
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideAuth(() => {
      const auth = initializeAuth(getApp(), {
        persistence: indexedDBLocalPersistence,
        popupRedirectResolver: browserPopupRedirectResolver,
      });
      if (environment.emulator) {
        connectAuthEmulator(auth, 'http://localhost:9099', {
          disableWarnings: true,
        });
      }
      return auth;
    })
...
],
...
  1. Try to create auth guards
// app-routing.module.ts

import {
  redirectLoggedInTo,
  canActivate,
} from '@angular/fire/compat/auth-guard';

const redirectToDashboard = () => {
  return redirectLoggedInTo('dashboard');
};

const routes: Routes = [
  {
    path: '',
    component: LandingPageComponent,
    ...canActivate(redirectToDashboard),
    data: { animation: 'Sign in' },
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
  exports: [RouterModule],
})
export class AppRoutingModule {}

Debug output

core.js:6479 ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(AppModule)[AngularFireAuthGuard -> AngularFireAuth -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options]: 
  NullInjectorError: No provider for InjectionToken angularfire2.app.options!
NullInjectorError: R3InjectorError(AppModule)[AngularFireAuthGuard -> AngularFireAuth -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options]: 
  NullInjectorError: No provider for InjectionToken angularfire2.app.options!
    at NullInjector.get (core.js:11101)
    at R3Injector.get (core.js:11268)
    at R3Injector.get (core.js:11268)
    at R3Injector.get (core.js:11268)
    at injectInjectorOnly (core.js:4751)
    at Module.ɵɵinject (core.js:4755)
    at Object.AngularFireAuth_Factory [as factory] (angular-fire-compat-auth.js:125)
    at R3Injector.hydrate (core.js:11438)
    at R3Injector.get (core.js:11257)
    at injectInjectorOnly (core.js:4751)
    at resolvePromise (zone.js:1213)
    at resolvePromise (zone.js:1167)
    at zone.js:1279
    at ZoneDelegate.invokeTask (zone.js:406)
    at Object.onInvokeTask (core.js:28659)
    at ZoneDelegate.invokeTask (zone.js:405)
    at Zone.runTask (zone.js:178)
    at drainMicroTaskQueue (zone.js:582)

Expected behavior

Mixing modular Auth with compat AuthGuards should not cause null injector error, or AngularFire should provide a modular AuthGuards too (along with a sample project).

Actual behavior

Mixing modularAuth with compat AuthGuards throws the following error: R3InjectorError (NullInjectorError: No provider for InjectionToken angularfire2.app.options!). If I remove AuthGuards from my app, the error goes away (but I don’t want to do that, obviously). Thank you for your answers in advance!

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:6
  • Comments:5

github_iconTop GitHub Comments

4reactions
rulaman123commented, Sep 30, 2021

For compat imports you need to import the ‘old’ modules. In your case: AngularFireModule.initializeApp(environment.firebase) and AngularFireAuthModule.

2reactions
adamfulopcommented, Oct 14, 2021

The above solution did not work for me, modified it slightly to make it work.

import {Injectable} from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from '@angular/router';
import {Observable, of, pipe, UnaryFunction} from 'rxjs';
import auth from "firebase/auth";
import {map, switchMap, take} from "rxjs/operators";
import {Auth, authState, getAuth} from "@angular/fire/auth";


export type AuthPipeGenerator = (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => AuthPipe;
export type AuthPipe = UnaryFunction<Observable<auth.User | null>, Observable<boolean | string | any[]>>;

export const loggedIn: AuthPipe = map(user => !!user);

@Injectable({
  providedIn: 'any'
})
export class AngularFireAuthGuard implements CanActivate {
  private readonly auth: Auth;
  private user$: Observable<auth.User | null>;

  constructor(private router: Router) {
    this.auth = getAuth();
    this.user$ = authState(this.auth);
  }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    const authPipeFactory = next.data.authGuardPipe as AuthPipeGenerator || (() => loggedIn);

    return this.user$.pipe(
      take(1),
      authPipeFactory(next, state),
      map(can => {
        if (typeof can === 'boolean') {
          return can;
        } else if (Array.isArray(can)) {
          return this.router.createUrlTree(can);
        } else {
          return this.router.parseUrl(can);
        }
      })
    );
  }

}

export const canActivate = (p: AuthPipeGenerator) => ({
  canActivate: [AngularFireAuthGuard], data: {authGuardPipe: p}
});

export const isNotAnonymous: AuthPipe = map(user => !!user && !user.isAnonymous);
export const idTokenResult = switchMap((user: auth.User | null) => user ? user.getIdTokenResult() : of(null));
export const emailVerified: AuthPipe = map(user => !!user && user.emailVerified);
export const customClaims = pipe(idTokenResult, map(idTokenResult2 => idTokenResult2 ? idTokenResult2.claims : []));
export const hasCustomClaim: (claim: string) => AuthPipe =
  (claim) => pipe(customClaims, map(claims => claims.hasOwnProperty(claim)));
export const redirectUnauthorizedTo: (redirect: string | any[]) => AuthPipe =
  (redirect) => pipe(loggedIn, map(loggedIn2 => loggedIn2 || redirect));
export const redirectLoggedInTo: (redirect: string | any[]) => AuthPipe =
  (redirect) => pipe(loggedIn, map(loggedIn2 => loggedIn2 && redirect || true));
Read more comments on GitHub >

github_iconTop Results From Across the Web

NullInjectorError: No provider for InjectionToken angularfire2 ...
The fix is actually really simple... in your app.module.ts. import import { FIREBASE_OPTIONS } from '@angular/fire/compat';.
Read more >
Bountysource
Modular Auth with compat AuthGuards throws R3InjectorError (NullInjectorError: No provider for InjectionToken angularfire2.app.options!)
Read more >
angular/angularfire2 - Gitter
Hey guys I am getting No provider for InjectionToken angularfire2.app.options in my test. I have added AngularFirestore as a provider in testBed. Aleksander....
Read more >
NG0201: No provider for {token} found! - Angular
This is commonly thrown in services, which require non-existing providers. To fix the error ensure that your service is registered in the list...
Read more >
AngularFire2 Authentication - KhoPhi's Blog
In summary, we're going to build a login, sign up AngularFire2 app with Route guards and a bit of Nested (Child) routes along...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found