Angular CLI Fullstack (NodeJS + Express + Mongoose) — Part 4

It’s time to work with both parts at the same time. For the past 3 parts we have focused mainly on the Backend. Now it is time to put our hard work to use in the Frontend.

Tasks

Here is what we will be covering in this part of the tutorial series:

  1. Create a Login Page
  2. Create a authentication function in the Backend that returns a token.
  3. Create an Authentication service in the Frontend to authenticate a user.
  4. Create a route guard to protect our routes.
  5. Create a Home Page, and activate the route guard to prevent unauthenticated users from viewing the home page.

Creating Pages

Using the Angular CLI we can generate a Login page and Home Page with the generator. The syntax is as follows:

ng generate [name] path/[itemname]

You can find more information on the Angular CLI generator pipelines here. We will be generating a component in this case. But for organization purposes, we will want to ensure we put it in a folder that makes it easy to determine where to find these components. In this case, the Login Page would be a view we want to route a user to, so we will place this into a ‘pages’ folder.

Run the following in the terminal:

ng generate component pages/LoginPage
ng generate component pages/HomePage
After generating HomePage and LoginPage

The Angular CLI took care of generating the necessary files to get this page setup. Now we want to be able to route to these two pages. Since upon generating this project, we used the routing flag. We have a file named app-routing.module.ts in our client/app folder. Let’s open it up and add some paths.

app-routing.module.ts file with component page routes.

Now we want to copy the content of app.component.html , except for the line that has the tag <router-outlet></router-outlet> , and paste it in the home-page.component.html file. This will simulate the view we will have once we log in to the web page.

Backend Authenticating

Since we have a functioning Backend. We can go ahead and set up our authentication function first prior to setting up the Login Page. We will want to set up first an authentication method in the UserSchema which is found in the user.model.js file. Inside the UserSchema.method object, add the following after one of the already existing functions:

Now we create a function in our user.controller.js file that will handle login requests. We want to first fineOne user by email, and then run the authenticate method from that retrieved user. If the user exists, we compare the user’s already encrypted password, with the given password after we run it through an encryption using the current user’s salt.

First, we will want to install the jsonwebtoken library and import it into the user.controller.js file, along with our config file so we can use the application secret key to sign the token if the user is authenticated. You will want to read up on token signing here to understand why we need a secret key.

So there is a lot going on. We do a couple of comparisons inside the authenticate callback. We check if there is an authErr during the authentication process. Then we check if the users is authenticated or not, with the given password. If he’s not, we return an invalid user message to the source. If the user is authenticated, then we will created an JSON Web Token that can be used to keep them authenticated. And we return a couple additional fields from the User model to use throughout our application.

Now we have to register this route in our user.routes.js file so that we can send a POST request. So add the following to the user.routes.js file.

router.post('/login', controller.login);

This will let us send the following POST request using postman and get a JSON response if it is valid.

Working authentication request returning a JSON web token and user info.

Authentication Service

Now let’s create the service that will communicate with our Backend. We will be preforming a basic HTTP JSON Web Token authentication.

Start by generating the Authentication Service file:

ng generate service services/auth

Now there will be an Auth service file under a new folder called services. But before we start coding, we want to add the HttpClientModule to our app.module.ts file. This Module will help us make HTTP requests.

importing HttpClientModule into app.module.ts

Now we can use the HttpClient import in our auth.service.ts file to make HTTP Requests.

auth.service.ts file

We import the HttpClient module here so that we can use it to send HTTP requests to a specific endpoint. In this case, the route for our login is /api/users/login. We add a private variable http in our constructor so we can use in our service.

We then create a function called login that takes in an email and password, composes an HTTP POST request and sends it off to our endpoint, returning the result.


Creating the Login Page

So now we want to work on our actual Login Page. But first, we will need to import the FormsModule into our app.module.ts file. The FormsModule helps us build forms in Angular.

Importing FormsModule into application imports.

Now we can start building the login form. Open up the paste the code below into the long-page.component.html file inside the login-page folder.

Login Page html
Login Page CSS

And now open login-page.component.ts and set up the two-way binding variables, And the login function that will send the user credentials for authentication.

login-page.component.ts file with login function testing return.

For now we are just going to test to see if we get the JSON Token response we want. You can open up the Login form, submit the credentials, and open up the console on the browser to test the output.

login page authentication.

So we receive the correct response, but what now? Well we would want to route the user to the login page if we managed to sign in right? This is where we can incorporate the Router object from angular to do some routing for us. Let’s also import ActivateRoute as well so we can jump a step ahead and set up redirects back to pages that requested the LoginPage.

import { Router, ActivatedRoute } from '@angular/router';

Now we want to declare some private variables for these imports in our constructor.

login-page.component.ts constructor import references.

Now we can use these imports in our file. What we want to do is use the already in place ngOnInit() function to check if this page was sent to the view from another page, there will be a parameter in the ‘returnUrl’ if we send it from another page. If there isn’t and it’s undefined, then let’s specify the return url to be the home page or ‘/.’

ngOnInit return URL snapshot

Now we can actually work on the login function. What we want to do is check the returned value from the API call, and if it is anything other than a valid login, clear the form. If the authentication is valid, let’s redirect the users to the HomePage.

The big thing to keep in mind is when we return the data from the API, if we have a bad login, we return an object with message equal to false. We can check this and reset the form, otherwise we can redirect the user to the home page.


Protecting routes

Now I mentioned that we wanted users to be logged in first to the application before viewing the home page. As of now, we have no current setup to protect our routes from unauthorized access. But we can set that up quite easily with a Route Guard. Route Guards are services that check for specific conditions before letting a user be routed to a specific view on the site.

First let’s generate a Route Guard called Auth.

ng generate guard guards/Auth

This will generate us a folder called guards with an AuthGuard inside. Let’s open up the auth.guard.ts file so we can see the contents.

auth.guard.ts initial file

It honestly does look like a lot at first. So much unknown code inside. But it is rather simple. Angular 2+ has a feature called canActivate and willActivate that let us check first for special conditions before activating a route. This saves us a lot of memory consumption if we check if a use can even enter a route, before loading it.

Remember how we saved the user in localStorage? What we will do, and although it is not the most secure, it will demonstrate us a simple authentication method for route protecting. Our AuthGuard will do the following.

  1. Check the localStorage for a ‘currentUser’ item.
  2. If it exists, then we allow access, otherwise we redirect to the login page.

Update the canActivate function in the AuthGuard to the following:

can activate authentication check

Implementing the Route Guard

Now all we have to do is update the app-routing.module.ts file. We will want to import the AuthGuard and pass it as an extra parameter to our route as such. We only add it to a specific path we want protected by this Route Guard. Otherwise all other routes will allow non authorized users to enter.

Now when a user tries to load our application and our HomePage, it will automatically redirect them to the LoginPage as they are not logged in. Once they log in, it will redirect them back to the home page.


Conclusion

Now you can implement more routes and protect them with this Authentication Guard. You can implement your own guards for these routes that have different requirements or rules to prevent users from accessing the page.