|  | 
|  | 1 | +# Route users with AngularFire guards | 
|  | 2 | + | 
|  | 3 | +`AngularFireAuthGuard` provides a prebuilt [`canActivate` Router Guard](https://angular.io/api/router/CanActivate) using `AngularFireAuth`. By default unauthenticated users are not permitted to navigate to protected routes: | 
|  | 4 | + | 
|  | 5 | +```ts | 
|  | 6 | +import { AngularFireAuthGuard } from '@angular/fire/auth-guard'; | 
|  | 7 | + | 
|  | 8 | +export const routes: Routes = [ | 
|  | 9 | +    { path: '',      component: AppComponent }, | 
|  | 10 | +    { path: 'items', component: ItemListComponent, canActivate: [AngularFireAuthGuard] }, | 
|  | 11 | +] | 
|  | 12 | +``` | 
|  | 13 | + | 
|  | 14 | +## Customizing the behavior of `AngularFireAuthGuard` | 
|  | 15 | + | 
|  | 16 | +To customize the behavior of `AngularFireAuthGuard`, you can pass an RXJS pipe through the route data's `authGuardPipe` key. | 
|  | 17 | + | 
|  | 18 | +The `auth-guard` module provides the following pre-built pipes: | 
|  | 19 | + | 
|  | 20 | +| Exported pipe                      | Functionality | | 
|  | 21 | +|-|-| | 
|  | 22 | +| `loggedIn`                         | The default pipe, rejects if the user is not authenticated. | | 
|  | 23 | +| `isNotAnonymous`                   | Rejects if the user is anonymous | | 
|  | 24 | +| `emailVerified`                    | Rejects if the user's email is not verified | | 
|  | 25 | +| `hasCustomClaim(claim)`            | Rejects if the user does not have the specified claim | | 
|  | 26 | +| `redirectUnauthorizedTo(redirect)` | Redirect unauthenticated users to a different route  | | 
|  | 27 | +| `redirectLoggedInTo(redirect)`     | Redirect authenticated users to a different route | | 
|  | 28 | + | 
|  | 29 | +Example use: | 
|  | 30 | + | 
|  | 31 | +```ts | 
|  | 32 | +import { AngularFireAuthGuard, hasCustomClaim, redirectUnauthorizedTo, redirectLoggedInTo } from '@angular/fire/auth-guard'; | 
|  | 33 | + | 
|  | 34 | +const adminOnly = hasCustomClaim('admin'); | 
|  | 35 | +const redirectUnauthorizedToLogin = redirectUnauthorizedTo(['login']); | 
|  | 36 | +const redirectLoggedInToItems = redirectLoggedInTo(['items']); | 
|  | 37 | +const belongsToAccount = (next) => hasCustomClaim(`account-${next.params.id}`); | 
|  | 38 | + | 
|  | 39 | +export const routes: Routes = [ | 
|  | 40 | +    { path: '',      component: AppComponent }, | 
|  | 41 | +    { path: 'login', component: LoginComponent,        canActivate: [AngularFireAuthGuard], data: { authGuardPipe: redirectLoggedInToItems }}, | 
|  | 42 | +    { path: 'items', component: ItemListComponent,     canActivate: [AngularFireAuthGuard], data: { authGuardPipe: redirectUnauthorizedToLogin }, | 
|  | 43 | +    { path: 'admin', component: AdminComponent,        canActivate: [AngularFireAuthGuard], data: { authGuardPipe: adminOnly }}, | 
|  | 44 | +    { path: 'accounts/:id', component: AdminComponent, canActivate: [AngularFireAuthGuard], data: { authGuardPipe: belongsToAccount }} | 
|  | 45 | +]; | 
|  | 46 | +``` | 
|  | 47 | +
 | 
|  | 48 | +Use the provided `canActivate` helper and spread syntax to make your routes more readable: | 
|  | 49 | +
 | 
|  | 50 | +```ts | 
|  | 51 | +import { canActivate } from '@angular/fire/auth-guard'; | 
|  | 52 | + | 
|  | 53 | +export const routes: Routes = [ | 
|  | 54 | +    { path: '',             component: AppComponent }, | 
|  | 55 | +    { path: 'login',        component: LoginComponent,    ...canActivate(redirectLoggedInToItems) }, | 
|  | 56 | +    { path: 'items',        component: ItemListComponent, ...canActivate(redirectUnauthorizedToLogin) }, | 
|  | 57 | +    { path: 'admin',        component: AdminComponent,    ...canActivate(adminOnly) }, | 
|  | 58 | +    { path: 'accounts/:id', component: AdminComponent,    ...canActivate(belongsToAccount) } | 
|  | 59 | +]; | 
|  | 60 | +``` | 
|  | 61 | +
 | 
|  | 62 | +### Compose your own pipes | 
|  | 63 | +
 | 
|  | 64 | +`AngularFireAuthGuard` pipes are RXJS operators which transform an optional User to a boolean or Array (for redirects). You can build easily build your own to customize behavior further: | 
|  | 65 | +
 | 
|  | 66 | +```ts | 
|  | 67 | +import { map } from 'rxjs/operators'; | 
|  | 68 | + | 
|  | 69 | +// This pipe redirects a user to their "profile edit" page or the "login page" if they're unauthenticated | 
|  | 70 | +// { path: 'profile', ...canActivate(redirectToProfileEditOrLogin) } | 
|  | 71 | +const redirectToProfileEditOrLogin = map(user => user ? ['profiles', user.uid, 'edit'] : ['login']); | 
|  | 72 | +``` | 
|  | 73 | +
 | 
|  | 74 | +The `auth-guard` modules provides a `customClaims` operator to reduce boiler plate when checking a user's claims: | 
|  | 75 | +
 | 
|  | 76 | +```ts | 
|  | 77 | +import { pipe } from 'rxjs'; | 
|  | 78 | +import { map } from 'rxjs/operators'; | 
|  | 79 | +import { customClaims } from '@angular/fire/auth-guard'; | 
|  | 80 | + | 
|  | 81 | +// This pipe will only allow users with the editor role to access the route | 
|  | 82 | +// { path: 'articles/:id/edit', component: ArticleEditComponent, ...canActivate(editorOnly) } | 
|  | 83 | +const editorOnly = pipe(customClaims, map(claims => claims.role === "editor")); | 
|  | 84 | +``` | 
|  | 85 | +
 | 
|  | 86 | +### Using router state | 
|  | 87 | +
 | 
|  | 88 | +`AngularFireAuthGuard` will also accept `AuthPipeGenerator`s which generate `AuthPipe`s given the router state: | 
|  | 89 | +
 | 
|  | 90 | +```ts | 
|  | 91 | +import { pipe } from 'rxjs'; | 
|  | 92 | +import { map } from 'rxjs/operators'; | 
|  | 93 | +import { customClaims } from '@angular/fire/auth-guard'; | 
|  | 94 | + | 
|  | 95 | +// Only allow navigation to the route if :userId matches the authenticated user's uid | 
|  | 96 | +// { path: 'user/:userId/edit', component: ProfileEditComponent, ...canActivate(onlyAllowSelf) } | 
|  | 97 | +const onlyAllowSelf = (next) => map(user => !!user && next.params.userId === user.uid); | 
|  | 98 | + | 
|  | 99 | +// Only allow navigation to the route if the user has a custom claim matching  :accountId | 
|  | 100 | +// { path: 'accounts/:accountId/billing', component: BillingDetailsComponent, ...canActivate(accountAdmin) } | 
|  | 101 | +const accountAdmin = (next) => pipe(customClaims, map(claims => claims[`account-${next.params.accountId}-role`] === "admin")); | 
|  | 102 | +``` | 
0 commit comments