angularfire: 5.2.1 AngularFireAuthGuard causes TypeError: source.lift is not a function

Performing basic docs for AngularFireAuthGuard produces an error related to source.lift.

Version info

sputnik:testauthguard katowulf$ npm list --depth 0
testauthguard@0.0.0 /Users/katowulf/projects/testauthguard
├── @angular-devkit/build-angular@0.11.4
├── @angular/animations@7.1.4
├── @angular/cli@7.1.4
├── @angular/common@7.1.4
├── @angular/compiler@7.1.4
├── @angular/compiler-cli@7.1.4
├── @angular/core@7.1.4
├── @angular/fire@5.2.1
├── @angular/forms@7.1.4
├── @angular/language-service@7.1.4
├── @angular/platform-browser@7.1.4
├── @angular/platform-browser-dynamic@7.1.4
├── @angular/router@7.1.4
├── @types/jasmine@2.8.16
├── @types/jasminewd2@2.0.6
├── @types/node@8.9.5
├── codelyzer@4.5.0
├── core-js@2.6.9
├── firebase@6.1.0
├── jasmine-core@2.99.1
├── jasmine-spec-reporter@4.2.1
├── karma@3.1.4
├── karma-chrome-launcher@2.2.0
├── karma-coverage-istanbul-reporter@2.0.5
├── karma-jasmine@1.1.2
├── karma-jasmine-html-reporter@0.2.2
├── protractor@5.4.2
├── rxjs@6.3.3
├── ts-node@7.0.1
├── tslib@1.9.3
├── tslint@5.11.0
├── typescript@3.1.6
└── zone.js@0.8.29

sputnik:testauthguard katowulf$ ng version

Angular CLI: 7.1.4
Node: 8.9.3
OS: darwin x64
Angular: 7.1.4
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.11.4
@angular-devkit/build-angular     0.11.4
@angular-devkit/build-optimizer   0.11.4
@angular-devkit/build-webpack     0.11.4
@angular-devkit/core              7.1.4
@angular-devkit/schematics        7.1.4
@angular/fire                     5.2.1
@ngtools/webpack                  7.1.4
@schematics/angular               7.1.4
@schematics/update                0.11.4
rxjs                              6.3.3
typescript                        3.1.6
webpack                           4.23.1

package.json

{
  "name": "testauthguard",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~7.1.0",
    "@angular/common": "~7.1.0",
    "@angular/compiler": "~7.1.0",
    "@angular/core": "~7.1.0",
    "@angular/fire": "^5.2.1",
    "@angular/forms": "~7.1.0",
    "@angular/platform-browser": "~7.1.0",
    "@angular/platform-browser-dynamic": "~7.1.0",
    "@angular/router": "~7.1.0",
    "core-js": "^2.5.4",
    "firebase": "^6.1.0",
    "rxjs": "~6.3.3",
    "tslib": "^1.9.0",
    "zone.js": "~0.8.26"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.11.0",
    "@angular/cli": "~7.1.0",
    "@angular/compiler-cli": "~7.1.0",
    "@angular/language-service": "~7.1.0",
    "@types/node": "~8.9.4",
    "@types/jasmine": "~2.8.8",
    "@types/jasminewd2": "~2.0.3",
    "codelyzer": "~4.5.0",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~3.1.1",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~1.1.2",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.4.0",
    "ts-node": "~7.0.0",
    "tslint": "~5.11.0",
    "typescript": "~3.1.6"
  }
}

How to reproduce these conditions

Failing test unit, Plunkr, or JSFiddle demonstrating the problem

testauthguard.zip Gist of app.module.ts and app-routing.module.ts here.

Steps to set up and reproduce

  1. Download and decompress zip file
  2. npm install
  3. npm start

How I created the contents of the zip:

ng new testauthguard
cd testauthguard
npm install @angular/fire firebase --save
ng generate component test
ng generate component login

Then I modified auth-routing.module.ts as indicated in the docs for AuthGuard.

Sample data and security rules

n/a

Debug output

** Errors in the JavaScript console **

ERROR Error: Uncaught (in promise): TypeError: source.lift is not a function
TypeError: source.lift is not a function
    at mapOperation (map.js:9)
    at pipe.js:18
    at Array.reduce (<anonymous>)
    at piped (pipe.js:18)
    at AngularFireAuthGuard.push../node_modules/@angular/fire/auth-guard/auth-guard.js.AngularFireAuthGuard.canActivate (auth-guard.js:23)
    at router.js:3097
    at Observable._subscribe (defer.js:9)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable._trySubscribe (Observable.js:43)
    at Observable.push../node_modules/rxjs/_esm5/internal/Observable.js.Observable.subscribe (Observable.js:29)
    at TakeOperator.push../node_modules/rxjs/_esm5/internal/operators/take.js.TakeOperator.call (take.js:24)
    at resolvePromise (zone.js:831)
    at resolvePromise (zone.js:788)
    at zone.js:892
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:16147)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
    at drainMicroTaskQueue (zone.js:601)
defaultErrorLogger @ core.js:14597
push../node_modules/@angular/core/fesm5/core.js.ErrorHandler.handleError @ core.js:14645
next @ core.js:16628
schedulerFn @ core.js:12609
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub @ Subscriber.js:196
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next @ Subscriber.js:134
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next @ Subscriber.js:77
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next @ Subscriber.js:54
push../node_modules/rxjs/_esm5/internal/Subject.js.Subject.next @ Subject.js:47
push../node_modules/@angular/core/fesm5/core.js.EventEmitter.emit @ core.js:12593
(anonymous) @ core.js:16178
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:391
push../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:150
push../node_modules/@angular/core/fesm5/core.js.NgZone.runOutsideAngular @ core.js:16115
onHandleError @ core.js:16178
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.handleError @ zone.js:395
push../node_modules/zone.js/dist/zone.js.Zone.runGuarded @ zone.js:164
_loop_1 @ zone.js:694
api.microtaskDrainDone @ zone.js:703
drainMicroTaskQueue @ zone.js:608
Promise.then (async)
scheduleMicroTask @ zone.js:584
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:413
push../node_modules/zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:238
push../node_modules/zone.js/dist/zone.js.Zone.scheduleMicroTask @ zone.js:258
scheduleResolveOrReject @ zone.js:879
ZoneAwarePromise.then @ zone.js:1012
push../node_modules/@angular/core/fesm5/core.js.PlatformRef.bootstrapModule @ core.js:16660
./src/main.ts @ main.ts:11
__webpack_require__ @ bootstrap:78
0 @ main.ts:12
__webpack_require__ @ bootstrap:78
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.js:1

** Output from firebase.database().enableLogging(true); **

n/a

** Screenshots **

Screen Shot 2019-06-02 at 1 21 13 PM

Expected behavior

Adding Auth guard should not generate an error for such a simple repro directly copying the docs.

Actual behavior

Addition of Auth guard causes error. Commenting it out removes the error.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 30
  • Comments: 39 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I worked in this way

const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(["login"]);

const routes: Routes = [
  {
    path: "home",
    children: [],
    canActivate: [AngularFireAuthGuard],
    data: { authGuardPipe: redirectUnauthorizedToLogin }
  }
]

I’ll be looking at this this week. Will aim to cut 5.2.2 with a fix for AOT ASAP.

These work locally and prod/SSR 👍

const isUser = () => pipe(map(user => {
  return !!user ? !!user : ['/'];
}));

const isAdmin = () => pipe(customClaims, map(claims => {
  return claims.admin === true ? claims.admin : ['/'];
}));

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'login', component: LoginComponent },
  {
    path: 'admin',
    component: AdminComponent,
    canActivate: [AngularFireAuthGuard],
    data: { authGuardPipe: isAdmin }
  },
  {
    path: 'profile',
    component: ProfileComponent,
    canActivate: [AngularFireAuthGuard],
    data: { authGuardPipe: isUser }
  },
  { path: '**', component: ErrorComponent }
];

Followed @jrodl3r comment and created own redirects.

const redirectUnauthorizedToLogin = () => map(user => !user ? ['login'] : true );
const redirectLoggedInToHome = () => map(user => !!user ? [''] : true );

. . .

const routes: Routes = [
  {
    path: '',
    component: HomePageComponent,
    canActivate: [AngularFireAuthGuard],
    data: { authGuardPipe: redirectUnauthorizedToLogin }
  },

etc...

Seems to work locally and in prod.

What about redirectLoggedInTo. How can I implement this?

I resolved the problem by replacing ...canActivate(redirectUnauthorizedToLogin) to ...canActivate(redirectUnauthorizedToLogin())

Any news on this? Its a bit odd to have the functionality straight from your documentation not working at all.

I worked in this way

const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(["login"]);

const routes: Routes = [
  {
    path: "home",
    children: [],
    canActivate: [AngularFireAuthGuard],
    data: { authGuardPipe: redirectUnauthorizedToLogin }
  }
]

Great, thanks for your help!

I was also able to get this working using the canActivate helper.

const redirectUnauthorizedToLogin = redirectUnauthorizedTo(['login']);

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', loadChildren: './home/home.module#HomePageModule', ...canActivate(redirectUnauthorizedToLogin) },
  { path: 'login', loadChildren: './login/login.module#LoginPageModule' },
];

EDIT: This actually failed to work when running in production mode. I seemed to have the same issue noted here: https://github.com/angular/angularfire2/issues/2114

For now the solution provided by @lisp719 works the best for me, even in production mode.

was so excited to implement the new and simplified auth guard… and that excitement landed me here with no solution , hope it gets resolved soon

I resolved the problem by replacing ...canActivate(redirectUnauthorizedToLogin) to ...canActivate(redirectUnauthorizedToLogin())

That would the the equivalent of just just not use the () => pipe syntax when defineing redirectUnauthorizedToLogin

const example1 = () => redirectUnauthorizedTo(['']);
const example2 = redirectUnauthorizedTo(['']);

// These would resolve the same
example1();
example2;

In my testing the biggest problem is how the pipe.name !== '' resolves in canActivate In Development example1 would yield example1 where as example2 would yield piped In both cases it would not satisfy pipe.name !== '' this the example1 getting () => added to it which does not seem intended.

However in my testing of production mode (which can be tested with ng serve --prod) pipe.name always resolves as '' which would break example2 since it requires the () => to be added to it to work.

So the result differs in development and production thus making this helper function not usable as is. What is required is either dropping the pipe.name !== '' or thinking of a better way to determine if pipe is already a function.

Hmmm, I’ll check this out, thanks for the repro Kato.

hello guys, how would i create a pipe that redirects the user if the email is not yet verified?


const redirectOrVerifyEmail = () =>
  map((user: any) => {
    return user && user.emailVerified ? ['speeches'] : ['auth/verify-email'];
  });

i’ve tried the code above but it returns an error

ERROR Error: "Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'auth/verify-email'

The docs now use the work around for AOT,

const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['login']);

https://github.com/angular/angularfire/blob/master/docs/auth/router-guards.md