TL;DR: In this article, we’ll explore Angular Console. Angular Console is a desktop application that provides a graphical UI for the Angular CLI. It is packed with features like code generation, task running, and a simple interface for installing CLI extensions like schematics. Angular Console is a great tool for Angular developers of all skill levels!

There’s often a bizarre prejudice in programming against graphical UIs in favor of the command line. Maybe it’s because of 80’s hacker movies, but it’s never made sense to me. A GUI is just a layer of abstraction. The computer gets the same commands whether you’re clicking on some buttons or furiously typing green text into a black screen.

Angular Console is a great reason to reconsider that bias. It’s a desktop application developed by Nrwl that provides a graphical UI for the Angular CLI. Nrwl is a software development consultancy that specializes in creating high-quality enterprise software. They’re also great at giving back to the Angular Community. Angular Console is packed with features like code generation, task running, and a simple interface for installing CLI extensions like schematics.

Who is Angular Console for?

When the team at Nrwl announced Angular Console, a lot of people shared a similar reaction. Sure, a GUI is fine for beginners (probably said with a sneer), but not the Advanced Super Users. I’m here to tell you that Angular Console is incredibly helpful for Angular developers across the experience spectrum.

"Angular Console by @nrwl_io is helpful for @angular devs of all experience levels."

It’s fantastic for new Angular friends

Okay, yes, let’s get this out there: Angular Console is great for folks new to Angular. Learning Angular can be tough, even with prior programming experience. Suddenly, you’re thrown into a world of TypeScript and RxJS observables on top of all of the normal front end development concerns. The Angular CLI is a lifesaver, but even that has a learning curve. The CLI has a specific syntax to learn, as well as all of the different commands needed to build applications. I don’t know about you, but the faster I can get up and running with a new framework, the more likely I am to stick with it.

Angular Console helps reduce the tooling friction of learning Angular to practically nothing. In just a few clicks, you can have a shiny new Angular application and open it in your favorite editor. You can then run CLI commands to generate things like components and services straight from Angular Console. You can even run and serve your app with a few clicks!

It’s a lifesaver for experienced Angular developers

Do you remember (without looking!) the command to use the NgRx schematics to generate a new action, but to use a flat directory structure and group all actions within one folder? How about the command to add a directive to a specific module while giving it a custom prefix?

Neither do I, at least not from memory. It’s the same reason I have to look up git rebase syntax nearly every time: I have more important things to worry about than memorizing a zillion commands!

In psychology, this is called being a cognitive miser. We humans prefer simplicity over complexity when it comes to processes and problem-solving. We can improve our ability to solve problems and finish tasks by reducing unnecessary complexity.

Angular Console helps reduce your cognitive overhead by providing a simple interface for generating code that includes live updating of CLI command output.

Here’s a screenshot of that command I mentioned to add a directive with a custom prefix to a specific module:

Generating a directive with Angular Console.

Note that I didn’t have to remember the name of the project, the path to the module, or the command to use a custom prefix. Angular Console handled all of that for me while showing me what it was doing under the hood. This becomes even more useful as your applications get larger, especially when trying to keep track of multiple projects and modules.

Angular Console also lets you quickly and easily add CLI extensions and schematics to your applications. There’s no more looking up exactly which package you need to install. If you want to add Angular Material, Ionic, NativeScript, or many others to your application, you can simply choose from a list and click “Add.” You’ll learn more about that in just a minute.

Naturally, the Nx schematics from Nrwl are tightly integrated into Angular Console. Nx schematics unlock all kinds of essential tools for enterprise developers, like the monorepo pattern, built-in support for testing with Jest and Cypress, and an incredible suite of scripts (like the ability to generate a dependency graph). Nx is definitely a power tool for the advanced user and Angular Console lets you wield it with ease and grace.

A Tour through Angular Console

Now that you know why Angular Console is so helpful, why don’t you take it for a test drive?

How to Install Angular Console

You’ll first need to head over to the Angular Console site to download and install it. It’s available as a desktop app for Mac, Windows, and Linux (the Linux app is still experimental), as well as an extension for Visual Studio Code. The requirements for running Angular Console are the same as running the Angular CLI, so you’ll need to download and install Node first.

Note: For this tour through Angular Console, I'll be using the dekstop version. The UI for the Visual Studio Code extension is a bit different, but all of the functionality is still there.

AngularConsole.com desktop app download options

How to Create a Project with Angular Console

Once you’ve got Angular Console installed, open it up. You’ll see a welcome screen that lets you choose between creating a new Angular workspace or opening an existing one.

The Angular Console welcome screen - create a project.

Click the create button. Select the parent directory you want to use and give a name to your new workspace (you can name it whatever you’d like). Angular Console will show you the path where your new workspace will live once it’s created.

Angular Console - Select a parent directory and give your workspace a name.

Click on step 3, “Choose a schematic set.” Here, Angular Console gives you the option to use either the default Angular schematics or Nrwl’s Nx schematics. As mentioned earlier, the Nx schematics create a monorepo and allow for some great other options for enterprise developers. For now, let’s keep things simple. Choose the default schematics.

Angular Console workspace - Choose the default schematics and click Create.

There's also an optional step 4, "Set schematic options." This includes options to skip the initial dependency installation, initialization of a git repostory, and many others.

You can keep it simple right now, though. Skip all of those and just click "Create."

You’ll see a bunch of output from the command line as the Angular CLI generates the application and runs npm install for you. Once that’s done, Angular Console will open the workspace for you.

Angular Console project automatically opens the workspace after setup.

If you click on the bar at the bottom (called the "action bar"), it will slide out as a bottom sheet and show you all of the command line output for running ng new to set up your workspace. This bar will appear any time you run a task. You can click on it to look at the output and then click the trash can icon to dismiss it.

In doing research for this article, I learned a couple of neat things about the action bar. I interviewed Nrwl engineer Dan Muller about Angular Console and it turns out this is his favorite feature in the app. Dan and his best friend Cindy were traveling together while they brainstormed on how to make this feature amazing. The action bar actually caches the last five tasks you ran. In addition to dismissing the output, there’s also a button that lets you re-run these tasks. Here’s an example from another project I have open:

Angular Console application listing up to five prior tasks.

Dan also put a lot of love into the UI design of this feature, like how the icons change if the task failed or was successful. The Angular Material library has no built-in bottom sheet, so he created it from scratch. You can really tell that Nrwl put a lot of care and attention into Angular Console, which developers like me really appreciate.

Okay, your new workspace is ready to go! Let’s look at how to use Angular Console.

Angular Console basics

Looking at the open project, you’ll notice a hamburger menu button in the upper left corner. That button takes you back to a list of workspaces, where you can also create or open a new workspace.

Below the main title bar, you’ll see a filter bar and a sorting button to organize projects. Of course, this brand new application only contains the main project and its e2e folder, so those aren’t terribly useful yet.

Below the filter and sorting bar, you’ll notice that there are a few buttons. To the right of the name of the main application, you’ll see buttons for “Serve,” “Test,” “Build,” and “Generate Component.” To the right of the end-to-end project name, you’ll see an “E2E” button. These buttons correspond to Angular CLI commands or npm scripts.

"Angular Console can generate code, run tasks, and install extensions."

The left toolbar is home to all of the core functionality of Angular Console.

The Angular Console app UI has buttons to get to a list of projects, code generation, task running, and extension installation.

The top list button you takes back to the list of projects in the open workspace (where you are now). The bottom gear button takes you to the settings screen. The chat bubble icon is where you can access Nrwl Connect, which is Nrwl’s premium support service. Nrwl Connect also unlocks some additional features in Angular Console.

The other three buttons are for generating code, running tasks, and installing extensions. Let’s step through each of these.

Generate code

You can use Angular Console to generate code in projects by clicking on the brackets icon in the left toolbar. This screen lists all available schematics, which you can also filter by name.

The Generate Code screen in Angular Console.

To try this, click on component under the standard @schematics/angular package. You’ll see a new screen with two sections: “Important fields” and “Optional fields.” You'll also see a collapsible bottom pane with a button that toggles between structured output or console output. The console output shows the generate command using the --dry-run flag and updates as you change options (so cool!). You can also hide this pane at any time with the caret button to the right.

Generating a component with Angular Console.

You’ll probably stick with the “Important fields” most of the time, but the “Optional fields” are where power users of the CLI will benefit. It can be tough to remember all of those extra flags and options. Angular Console’s live updating of the dry run output is extremely useful, too. Sometimes I just use Angular Console as a staging area for the commands I want to run and then copy and paste them into my terminal.

To generate a component from this screen, fill out a name and select the main project (not the e2e one). You can leave everything else with the default values, but feel free to experiment to see how the console output changes. When you’re ready, click “Generate” in the upper right corner. You’ll see the command change to drop the dry run and execute in the console. If you toggle the bottom pane to “Structured Output,” you’ll see that the task completed successfully.

Successful component generation in Angular Console.

Click the “X” in the upper left corner to return to the code generation screen. The task output is still available to you from the action bar you saw earlier.

Run tasks

Code generation is really awesome, but it’s only one of the features of Angular Console. You can also use Angular Console to run tasks. Click on the terminal icon in the left toolbar to get started. You’ll see a list of package.json scripts, as well as tasks related to the main project and the e2e project. You can also filter by name like on the other screens.

The task runner screen in Angular Console.

Search for “serve” and click on the task under the main project you created. You’ll see a screen similar to the one you saw when generating code. The familiar “Important fields” and “Optional fields” will be present, as well as the output pane. You’ll also see radio buttons for the serve task to either run with the default or production configuration.

The individual task screen in Angular Console.

Just as with the code generation screen, you’ll most likely stick with the standard fields as you get started. That being said, there are a wealth of options just for the serve command, like the port, the host, SSL settings, and settings specific to the underlying Webpack build. When you run ng serve or its cousin ng build from the terminal, you may not realize just how much granular control you can have on the CLI build. Having a UI really helps with that.

Once you’ve got the settings how you want them, click the “Run” button in the upper right corner. You’ll see the successful Console Output, as well as some new information from the Structured Output. You can click on the provided link to view your application in the browser at localhost:4200. If you make changes to your code, Angular Console will also let you know when the application rebuilds.

The task output of the serve command.

Click the “X” in the upper left corner to return to the task runner screen. The task is again available to you from the action bar. This time, since the server is in watch mode, you’ll see the spinning progress circle inside of a button on the left side. You can stop the serve task any time by clicking that button.

Install extensions

Last but not least, Angular Console features an easy way to install other extensions and schematics packages in your workspace. Click on the puzzle piece in the left toolbar to go to the extensions screen. You’ll see a long list of available extensions from the Angular team, outside companies, and members of the community. Whether you need to add state management, a UI library, or mobile support, you can search through the list and install the package you need with ease. You can also install Nrwl’s Nx schematics to convert your default CLI workspace into an Nx workspace.

Angular Console extensions screen.

To try this out, search for “material” and click on the @angular/material package. You’ll see the familiar UI, but without any additional options.

The screen to add Angular Material.

Click the “Add” button in the upper right corner. You’ll see the installation output in the console, as well as “Task completed successfully” in the Structured Output.

Angular Material was added successfully!

Clicking on the “X” in the upper left corner will take you back to the extension installation screen. You’ll also see your completed task added to the bottom task list. You can clear that list any time by clicking on the bar to pop out the bottom sheet and clicking the trash can button. Note that clearing out the list will also stop any running tasks like ng serve.

If you install extensions that include CLI schematics, such as Nx or NgRx, you'll also see new tasks available from the Task Runner screen.

Conclusion

I hope this tour of Angular Console has given you some ideas of how it can be useful to you. If you’re new to Angular, I hope Angular Console will become a great learning tool that helps you get up and running quickly with Angular. If you’re experienced with Angular, I hope you’ll see it as a timesaver and a cheatsheet for CLI commands. If you can’t stand GUIs and want to stick to the command line, that’s okay too. Whatever you choose, happy coding everyone!

Special thanks to Dan Muller from Nrwl for talking through some of the features and engineering decisions of Angular Console with me. Dan can be reached at dan@nrwl.io.

Aside: Authenticate an Angular App and Node API with Auth0

We can protect our applications and APIs so that only authenticated users can access them. Let's explore how to do this with an Angular application and a Node API using Auth0. You can clone this sample app and API from the angular-auth0-aside repo on GitHub.

Auth0 login screen

Features

The sample Angular application and API has the following features:

  • Angular application generated with Angular CLI and served at http://localhost:4200
  • Authentication with auth0.js using a login page
  • Node server protected API route http://localhost:3001/api/dragons returns JSON data for authenticated GET requests
  • Angular app fetches data from API once user is authenticated with Auth0
  • Profile page requires authentication for access using route guards
  • Authentication service uses subjects to provide authentication and profile data to the app

Sign Up for Auth0

You'll need an Auth0 account to manage authentication. You can sign up for a free account here. Next, set up an Auth0 application and API so Auth0 can interface with an Angular app and Node API.

Set Up an Auth0 Application

  1. Go to your Auth0 Dashboard: Applications section and click the "+ Create Application" button.
  2. Name your new app and select "Single Page Web Applications".
  3. In the Settings for your new Auth0 app, add http://localhost:4200/callback to the Allowed Callback URLs.
  4. Add http://localhost:4200 to both the Allowed Web Origins and Allowed Logout URLs. Click the "Save Changes" button.
  5. If you'd like, you can set up some social connections. You can then enable them for your app in the Application options under the Connections tab. The example shown in the screenshot above uses username/password database, Facebook, Google, and Twitter.

Note: Set up your own social keys and do not leave social connections set to use Auth0 dev keys or you will encounter issues with token renewal.

Set Up an API

  1. Go to APIs in your Auth0 dashboard and click on the "Create API" button. Enter a name for the API. Set the Identifier to your API endpoint URL. In this example, this is http://localhost:3001/api/. The Signing Algorithm should be RS256.
  2. You can consult the Node.js example under the Quick Start tab in your new API's settings. We'll implement our Node API in this fashion, using Express, express-jwt, and jwks-rsa.

We're now ready to implement Auth0 authentication on both our Angular client and Node backend API.

Dependencies and Setup

The Angular app utilizes the Angular CLI. Make sure you have the CLI installed globally:

$ npm install -g @angular/cli

Once you've cloned the project on GitHub, install the Node dependencies for both the Angular app and the Node server by running the following commands in the root of your project folder:

$ npm install
$ cd server
$ npm install

The Node API is located in the /server folder at the root of our sample application.

Find the config.js.example file and remove the .example extension from the filename. Then open the file:

// server/config.js (formerly config.js.example)
module.exports = {
  CLIENT_DOMAIN: '[YOUR_AUTH0_DOMAIN]', // e.g., 'you.auth0.com'
  AUTH0_AUDIENCE: 'http://localhost:3001/api/'
};

Change the CLIENT_DOMAIN value to your full Auth0 domain and set the AUTH0_AUDIENCE to your audience (in this example, this is http://localhost:3001/api/). The /api/dragons route will be protected with express-jwt and jwks-rsa.

Note: To learn more about RS256 and JSON Web Key Set, read Navigating RS256 and JWKS.

Our API is now protected, so let's make sure that our Angular application can also interface with Auth0. To do this, we'll activate the src/environments/environment.ts.example file by deleting .example from the file extension. Then open the file and change the [YOUR_CLIENT_ID] and [YOUR_AUTH0_DOMAIN] strings to your Auth0 information:

// src/environments/environment.ts (formerly environment.ts.example)
...
export const environment = {
  production: false,
  auth: {
    CLIENT_ID: '[YOUR_CLIENT_ID]',
    CLIENT_DOMAIN: '[YOUR_AUTH0_DOMAIN]', // e.g., 'you.auth0.com'
    ...
  }
};

Our app and API are now set up. They can be served by running ng serve from the root folder and node server from the /server folder. The npm start command will run both at the same time for you by using concurrently.

With the Node API and Angular app running, let's take a look at how authentication is implemented.

Authentication Service

Authentication logic on the front end is handled with an AuthService authentication service: src/app/auth/auth.service.ts file. We'll step through this code below.

// src/app/auth/auth.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, bindNodeCallback, of } from 'rxjs';
import * as auth0 from 'auth0-js';
import { environment } from './../../environments/environment';
import { Router } from '@angular/router';

@Injectable()
export class AuthService {
  // Create Auth0 web auth instance
  // @TODO: Update environment variables and remove .example
  // extension in src/environments/environment.ts.example
  private _Auth0 = new auth0.WebAuth({
    clientID: environment.auth.CLIENT_ID,
    domain: environment.auth.CLIENT_DOMAIN,
    responseType: 'id_token token',
    redirectUri: environment.auth.REDIRECT,
    audience: environment.auth.AUDIENCE,
    scope: 'openid profile email'
  });
  // Track whether or not to renew token
  private _authFlag = 'isLoggedIn';
  // Create stream for token
  token$: Observable<string>;
  // Create stream for user profile data
  userProfile$ = new BehaviorSubject<any>(null);
  // Authentication navigation
  onAuthSuccessUrl = '/';
  onAuthFailureUrl = '/';
  logoutUrl = environment.auth.LOGOUT_URL;
  // Create observable of Auth0 parseHash method to gather auth results
  parseHash$ = bindNodeCallback(this._Auth0.parseHash.bind(this._Auth0));
  // Create observable of Auth0 checkSession method to
  // verify authorization server session and renew tokens
  checkSession$ = bindNodeCallback(this._Auth0.checkSession.bind(this._Auth0));

  constructor(private router: Router) { }

  login() {
    this._Auth0.authorize();
  }

  handleLoginCallback() {
    if (window.location.hash && !this.authenticated) {
      this.parseHash$().subscribe(
        authResult => {
          this._setAuth(authResult);
          window.location.hash = '';
          this.router.navigate([this.onAuthSuccessUrl]);
        },
        err => this._handleError(err)
      )
    }
  }

  private _setAuth(authResult) {
    // Observable of token
    this.token$ = of(authResult.accessToken);
    // Emit value for user data subject
    this.userProfile$.next(authResult.idTokenPayload);
    // Set flag in local storage stating this app is logged in
    localStorage.setItem(this._authFlag, JSON.stringify(true));
  }

  get authenticated(): boolean {
    return JSON.parse(localStorage.getItem(this._authFlag));
  }

  renewAuth() {
    if (this.authenticated) {
      this.checkSession$({}).subscribe(
        authResult => this._setAuth(authResult),
        err => {
          localStorage.removeItem(this._authFlag);
          this.router.navigate([this.onAuthFailureUrl]);
        }
      );
    }
  }

  logout() {
    // Set authentication status flag in local storage to false
    localStorage.setItem(this._authFlag, JSON.stringify(false));
    // This does a refresh and redirects back to homepage
    // Make sure you have the logout URL in your Auth0
    // Dashboard Application settings in Allowed Logout URLs
    this._Auth0.logout({
      returnTo: this.logoutUrl,
      clientID: environment.auth.CLIENT_ID
    });
  }

  private _handleError(err) {
    if (err.error_description) {
      console.error(`Error: ${err.error_description}`);
    } else {
      console.error(`Error: ${JSON.stringify(err)}`);
    }
  }

}

This service uses the auth config variables from environment.ts to instantiate an auth0.js WebAuth instance. Next an _authFlag member is created, which is simply a flag that we can store in local storage. It tells us whether or not to attempt to renew tokens with the Auth0 authorization server (for example, after a full-page refresh or when returning to the app later). All it does is state, "This front-end application thinks this user is authenticated" and then allows us to apply logic based on that estimation and verify whether or not it's accurate.

We'll add and type a token$ observable, which will provide a stream of the access token string. This is for use with the token interceptor. We don't want our interceptor to utilize a stream that emits a default value without any useable values. We'll declare token$ in our _setAuth() method below, when the access token becomes available.

We will use an RxJS BehaviorSubject to provide a stream of the user profile that you can subscribe to anywhere in the app. We'll also store some paths for navigation so the app can easily determine where to send users when authentication succeeds, fails, or the user has logged out.

The next thing that we'll do is create observables of the auth0.js methods parseHash() (which allows us to extract authentication data from the hash upon login) and checkSession() (which allows us to acquire new tokens when a user has an existing session with the authorization server). Using observables with these methods allows us to easily publish authentication events and subscribe to them within our Angular application.

We'll create observables of the callbacks from these two auth0.js methods using using RxJS's bindNodeCallback. In order to preserve the scope of this, we'll bind() it like so:

bindNodeCallback(this._Auth0.parseHash.bind(this._Auth0))

The login() method authorizes the authentication request with Auth0 using the environment config variables. A login page will be shown to the user and they can then authenticate.

Note: If it's the user's first visit to our app and our callback is on localhost, they'll also be presented with a consent screen where they can grant access to our API. A first party client on a non-localhost domain would be highly trusted, so the consent dialog would not be presented in this case. You can modify this by editing your Auth0 Dashboard API Settings. Look for the "Allow Skipping User Consent" toggle.

We'll receive accessToken, expiresIn, and idTokenPayload in the URL hash from Auth0 when returning to our app after authenticating at the login page. The handleLoginCallback() method subscribes to the parseHash$() observable to stream authentication data (_setAuth()) by creating our token$ observable and emitting a value for the userProfile$ behavior subject. This way, any subscribed components in the app are informed that the token and user data has been updated. The _authFlag is also set to true and stored in local storage so if the user returns to the app later, we can check whether to ask the authorization server for a fresh token. Essentially, the flag serves to tell the authorization server, "This app thinks this user is authenticated. If they are, give me their data." We check the status of the flag in local storage with the accessor method authenticated.

Note: The user profile data takes the shape defined by OpenID standard claims.

The renewAuth() method, if the _authFlag is true, subscribes to the checkSession$() observable to ask the authorization server if the user is indeed authorized (we can pass arguments to this observable as we would to the auth0.js function). If they are, fresh authentication data is returned and we'll run the _setAuth() method to update the necessary authentication streams in our app. If the user is not authorized with Auth0, the _authFlag is removed and the user will be redirected to the URL we set as the authentication failure location.

Next, we have a logout() method that sets the _authFlag to false and logs out of the authentication session on Auth0's server. The Auth0 logout() method then redirects back to the location we set as our logoutUrl.

Once AuthService is provided in app.module.ts, its methods and properties can be used anywhere in our app, such as the home component.

Callback Component

The callback component is where the app is redirected after authentication. This component simply shows a loading message until the login process is completed. It executes the authentication service's handleLoginCallback() method to parse the hash and extract authentication information.

// src/app/callback/callback.component.ts
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../auth/auth.service';

@Component({
  selector: 'app-callback',
  template: `<div>Loading...</div>`,
  styles: []
})
export class CallbackComponent implements OnInit {
  constructor(private auth: AuthService) { }

  ngOnInit() {
    this.auth.handleLoginCallback();
  }

}

Making Authenticated API Requests

In order to make authenticated HTTP requests, it's necessary to add an Authorization header with the access token to our outgoing requests. Note that the api.service.ts file does not do this.

Instead, this functionality is in an HTTP interceptor service called token.interceptor.ts.

// src/app/auth/token.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { AuthService } from './auth.service';
import { Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

@Injectable()
export class InterceptorService implements HttpInterceptor {
  constructor(private auth: AuthService) { }

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    // @NOTE: If you have some endpoints that are public
    // and do not need Authorization header, implement logic
    // here to accommodate that and conditionally let public
    // requests pass through based on your requirements
    return this.auth.token$
      .pipe(
        mergeMap(token => {
          if (token) {
            const tokenReq = req.clone({
              setHeaders: { Authorization: `Bearer ${token}` }
            });
            return next.handle(tokenReq);
          }
        })
      );
  }
}

As mentioned above, we can return the token$ observable to acquire a token, then clone the outgoing HTTP request and attach an Authorization header before sending the request on its way.

The interceptor should be provided like so in the app-routing.module.ts file:

// src/app/app-routing.module.ts
...
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { InterceptorService } from './auth/token.interceptor';
...

@NgModule({
  imports: [...],
  providers: [
    ...,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: InterceptorService,
      multi: true
    }
  ],
  ...
})
export class AppRoutingModule {}

Note: We set multi to true because we could implement multiple interceptors, which would run in the order of declaration.

Final Touches: Route Guard and Profile Page

A profile page component can show an authenticated user's profile information. However, we only want this component to be accessible if the user is logged in.

With an authenticated API request and login/logout implemented in the Home component, the final touch is to protect our profile route from unauthorized access. The auth.guard.ts route guard can check authentication and activate routes conditionally. The guard is implemented on specific routes of our choosing in the app-routing.module.ts file like so:

// src/app/app-routing.module.ts
...
import { AuthGuard } from './auth/auth.guard';
...

@NgModule({
  imports: [
    RouterModule.forRoot([
      ...,
      {
        path: 'profile',
        component: ProfileComponent,
        canActivate: [
          AuthGuard
        ]
      },
      ...
    ])
  ],
  providers: [
    AuthGuard,
    ...
  ],
  ...
})
export class AppRoutingModule {}

To Do: Elegant Error Handling

Now that the primary functionality is there, you'll want to think about gracefully handling and reacting to errors. Some functionality will need to be implemented for this. The errors are there to react to, but you'll want to consider how you prefer to respond to them when they occur.

More Resources

That's it! We have an authenticated Node API and Angular application with login, logout, profile information, and a protected route. To learn more, check out the following resources: