Performing basic docs for AngularFireAuthGuard produces an error related to source.lift.
sputnik:testauthguard katowulf$ npm list --depth 0
[email protected] /Users/katowulf/projects/testauthguard
βββ @angular-devkit/[email protected]
βββ @angular/[email protected]
βββ @angular/[email protected]
βββ @angular/[email protected]
βββ @angular/[email protected]
βββ @angular/[email protected]
βββ @angular/[email protected]
βββ @angular/[email protected]
βββ @angular/[email protected]
βββ @angular/[email protected]
βββ @angular/[email protected]
βββ @angular/[email protected]
βββ @angular/[email protected]
βββ @types/[email protected]
βββ @types/[email protected]
βββ @types/[email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
βββ [email protected]
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"
}
}
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
npm installnpm startHow 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
* 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 *

Adding Auth guard should not generate an error for such a simple repro directly copying the docs.
Addition of Auth guard causes error. Commenting it out removes the error.
Hmmm, I'll check this out, thanks for the repro Kato.
If I use ... canActivate (redirectUnauthorizedToLogin) will work perfectly.
But it is only working on localhost.
When the build is done --prod does not work
The route guardian is allowing access to the routes
ng serve localhost - work
ng build localhost - work
ng build firebase - work
ng build --prod localhost - fail
ng build --prod firebase - fail
i got the same error msg when using angularfireauthguard even when using ... canActivate (redirectUnauthorizedToLogin)
I have the same issue either with canActivate or authGuardPipe.
Having the same issue
I have the same issue
Also having the same issue
Π£ ΠΌΠ΅Π½Ρ ΡΠ°ΠΊΠ°Ρ ΠΆΠ΅ ΠΎΡΠΈΠ±ΠΊΠ° ΠΏΡΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ data: { authGuardPipe: redirectUnauthorizedToLogin }
...canActivate(redirectUnauthorizedToLogin) ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡ ΡΡΠΎ Π²ΡΡ ΡΠ΅ΡΠ°Π΅Ρ
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'll be looking at this this week. Will aim to cut 5.2.2 with a fix for AOT ASAP.
I worked in this way
const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(["login"]);
const routes: Routes = [
{
path: "home",
children: [],
canActivate: [AngularFireAuthGuard],
data: { authGuardPipe: redirectUnauthorizedToLogin }
}
]
Great lisp719 ! Your solution worked for me too! Thanks!!!!
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.
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 }
];
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!
Im trying to use the AF AuthGuard and I'm trying to protect a route from not logged in users and not admin users. To redirect the users when not logged in I use const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['login']); but how do I choose where to redirect the users when not admin?
What about redirectLoggedInTo. How can I implement this?
I had same issue and is not resolved by solution proposed, my routes are:
const redirectUnauthorizedToLogin = redirectUnauthorizedTo(['access']);
const appRoutes: Routes = [
{
path: 'access',
loadChildren: () => import('./main/authentication/auth.module').then(m => m.AuthModule),
},
{
path: '',
loadChildren: () => import('./main/pages/pages.module').then( m => m.PagesModule),
...canActivate(redirectUnauthorizedToLogin)
},
{
path : '**',
redirectTo: 'access'
}
];
AuthModule and PagesModule had GuardRedirects also.
Everything worked perfectly while serving, but when build with prod configuration guards did not trigger, neither this way or this other:
canActivate: [AngularFireAuthGuard],
data: { authGuardPipe: redirectUnauthorizedToLogin}
As the only difference between scenarios is build options, i tryed by test/error removing options.
Removing this two finally worked:
"aot": true,
"buildOptimizer": true,
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.
It works! Thank you @third-estate !
Any news on this? Its a bit odd to have the functionality straight from your documentation not working at all.
This is the point
const redirectUnauthorizedToLogin = redirectUnauthorizedTo(['login']);
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
To me, it seems like a similar issue posted on the Angular repo about using concat in route guards. I think this may be an Angular bug... https://github.com/angular/angular/issues/29374
@lisp719 's comment was what worked for me as well.
Any suggestions for using redirectLoggedInTo? Using the following code helper doesn't seem to work:
const redirectLoggedInToDashboard = () => redirectLoggedInTo(['dashboard']);
...canActivate(redirectLoggedInToDashboard)
I get the same TypeError: source.lift is not a function here.
`
import { redirectUnauthorizedTo, canActivate, AngularFireAuthGuard } from '@angular/fire/auth-guard';
const redirectUnauthorizedToLogin = () => redirectUnauthorizedTo(['login']);
const routes: Routes = [
{
path: '',
redirectTo: 'home',
pathMatch: 'full'
},
{ path: 'home',
loadChildren: './pages/home/home.module#HomePageModule',
canActivate: [AngularFireAuthGuard],
data: { authGuardPipe: redirectUnauthorizedToLogin }
},
{ path: 'entrance', loadChildren: './pages/entrance/entrance.module#EntrancePageModule' },
{ path: 'register', loadChildren: './pages/register/register.module#RegisterPageModule' },
{ path: 'login', loadChildren: './pages/login/login.module#LoginPageModule' }
];
`
I have it this way, no error in console and doesn't redirect unauthorized users. Any help please? Its the only thing remaining with my project.
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'
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'
I think this does not belong to this issue. This solution should work but perhaps with this syntax:
['auth', 'verify-email']
or there is a mistake in your routing.
I think the problem is this line
https://github.com/angular/angularfire/blob/master/src/auth-guard/auth-guard.ts#L28
authGuardPipe: pipe.name === ""
what the ...canActivate( needs to know if the function that is being passed is a factory function or simply a rxjs pipe.
To do this they used pipe.name === '' the problem is that in the latest version of rxjs the returned function name of the rxjs is piped which means that the ...canActivate function tries to run pass the factory function to the rxjs pipe and it fails.
I tried copying the canActivate function and changing to`pipe.name === 'piped' which works in development mode, but then fails in production, which i think is because of minification.
So the solution would be to change how to know when the function passed to canActivate is a factory function and when it's just a observable stream.
Anyhow, the solution with skipping using the ...canActivate function should work.
Still having the same issues, it's now 2020 is this getting fixed? if not it should be removed from the docs temporarily
After playing around with the source code I have found somewhat what is causing this error.
On these lines:
https://github.com/angular/angularfire/blob/master/src/auth-guard/auth-guard.ts#L27-L29
You will notice the ternary of pipe.name === '' ? pipe : () => pipe
Well it turns out when this resolves to () => pipe it causes the issue.
However if you remove the ternary and resolve to pipe then the issue does not occur.
My question is why would you need a function that returns the pipe?
There isn't a comment in this section to describe why a function would be needed.
Maybe it should have been pipe.name !== '' ? pipe : () => pipe?
Either way I will be using this custom helper in my code till this is resolved.
const canActivate = (pipe: AuthPipe | AuthPipeGenerator) => ({
canActivate: [AngularFireAuthGuard],
data: { authGuardPipe: pipe.name !== '' ? pipe : () => pipe },
});
Update:
This code seems to work for me without the source.lift error.
Notice how the redirectUnauthorizedToLogin and other definitions are not () => redirectUnauthorizedTo(['']) but instead just redirectUnauthorizedTo([''])
I believe the issue does lie with that turnery giving false positives. It seems like it was intending to check if it was in this format or the () => pipe format already but failing to do so with the pipe.name check.
const redirectUnauthorizedToLogin = redirectUnauthorizedTo(['']);
const redirectLoginToDashboard = redirectLoggedInTo(['dashboard']);
const adminOnly = hasCustomClaim('admin');
const routes: Routes = [
{
path: 'admin',
loadChildren: () => import('@story-squad/pages').then((m) => m.AdminModule),
...canActivate(adminOnly),
},
{
path: 'dashboard',
loadChildren: () => import('@story-squad/pages').then((m) => m.DashboardModule),
...canActivate(redirectUnauthorizedToLogin),
},
{
path: '',
loadChildren: () => import('@story-squad/pages').then((m) => m.LoginModule),
...canActivate(redirectLoginToDashboard),
},
];
Update:
After testing in production it seems that pipe.name is always an empty string. This appears to be the difference in behavior between production and development, thus I believe something like this would work in both production and development.
const canActivate = (authGuardPipe: AuthPipe | AuthPipeGenerator) => ({
canActivate: [AngularFireAuthGuard],
data: { authGuardPipe },
});
This will require you to use this format when declaring the pipes:
const adminOnly = () => hasCustomClaim('admin');
I resolved the problem by replacing
...canActivate(redirectUnauthorizedToLogin)
to
...canActivate(redirectUnauthorizedToLogin())
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.
Yes i got around a bunch of these issues with the lazy solution of wrapping things in a lodash _.constant.
Which is just a value function.
If actually fixing the issue is a problem. Why not just add the different syntax to the readme? Its not like its significantly more complicated, its like one extra line of code compared to the ...canActivate() method.
I resolved the problem by replacing
...canActivate(redirectUnauthorizedToLogin)
to
...canActivate(redirectUnauthorizedToLogin())That would the the equivalent of just just not use the
() => pipesyntax when defineingredirectUnauthorizedToLogin
Thanks to @ismailkoksal & @wSedlacek: ng build --prod is successful using either solution.
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
Can say that this still the solution for this issue..
Should be addressed with our pipe changes in 6.0
Most helpful comment
I worked in this way