As long as your final function adheres to the AuthPipe
interface (mapping Observable<firebase.User | null>
to Observable<boolean | string | string[]>
) you can compose any custom pipe.
The solution I went for used:
pipe
operator to pipe into the final AuthPipe
interface.
forkJoin
to join together the results from multiple AngularFireAuth
pipes.
map
to convert the intermediary results to boolean | string | string[]
.
With this approach you can use the results of multiple AuthPipe
s when implementing canActivate
logic.
(essentially a cleaner version of @pixelbits answer)
import { AngularFireAuthGuard, AuthPipe, emailVerified, loggedIn } from '@angular/fire/compat/auth-guard';
import { forkJoin, of, pipe } from 'rxjs';
const combined: AuthPipe = pipe(
mergeMap((user) => forkJoin([loggedIn(of(user)), emailVerified(of(user))])),
map(([isLoggedIn, isEmailVerified]) => {
console.log({ isLoggedIn, isEmailVerified });
if (!isLoggedIn) {
return '/auth/login';
}
if (!isEmailVerified) {
return '/auth/verify-email';
}
return true;
}),
);
// usage
{
component: MyComponent,
canActivate: [AngularFireAuthGuard],
data: { authGuardPipe: () => combined },
},
A note on the customClaims
AuthPipe
: it expects firebase.User
(does not allow for null
), so you can either:
- Use a ternary operator:
user ? customClaims(of(user)) : of(null)
or
- Call anyways
customClaims(of(user as any))
, which returns an empty array when user is null (source)