I will assume that you already have your Front with Angular 10 and your Back with Node.js ExpressJS 4 and I will not show the creation part of these two projects.
Creating the login form under Angular
The back side of the form :
Go to your form.component.ts file (Make it according to your components…) and we will build it as on the example :
import { Component, OnInit } from '@angular/core'; // Import of FormBuilder to build the form import { FormBuilder } from '@angular/forms'; @Component({ selector: 'app-login-form', templateUrl: './login-form.component.html', styleUrls: ['./login-form.component.scss'] }) export class LoginFormComponent implements OnInit { // required field email: String = ''; password: String = ''; // our form loginForm; constructor(private formBuilder: FormBuilder) { // During the creation of the component we define the form, without validation, the tutorial will not deal with this part. this.loginForm = this.formBuilder.group({ email: '', password: '' }); } ngOnInit(): void {} }
We see that we import the form builder which is none other than the FormBuilder, we instantiate our form variables and define the basis of the form from the FormBuilder.
The front side of the form :
<div id="login"> <h1>Login form</h1> // The notion formGroup defines to which variable the form is built in the back side of the form. <form [formGroup]="loginForm"> <div class="form-input"> <label for="email">Email</label> // The formControlName concept allows us to tell our formBuilder to which variable the input data is linked. // The tag [(ngModel)]="email" allows, when modifying the email in the input, to update the data of the variable <input type="text" formControlName="email" [(ngModel)]="email"> </div> <div class="form-input"> // See email these are the same explanations <label for="password">Password</label> <input type="password" formControlName="password" [(ngModel)]="password"> </div> // The (click)="submit" indicates that when the button is clicked, the submit() function will be launched. <button type="button" (click)="submit()">Submit</button> </form> </div>
We create a basic form with the directives formGroup, formControlName and ngModel which are new and explained in the code, we will continue and create the login service that will interact with the ExpressJS server.
Login service and server submission function:
Before writing the function of submitting the login to the server, you must write a login service. This will allow us if we want to reuse it in another place of our Angular components.
import { Injectable } from '@angular/core'; // To send HTTP request import { HttpClient } from '@angular/common/http'; @Injectable({ providedIn: 'root' }) export class LoginService { // User will be stocked here currentUser; // The jwt token here token; // the url to the api, don't forget the http:// /!\ urlApi = 'http://localhost:3000/api/'; constructor(private http: HttpClient) { } login(data) { // This function will be called in our form submission, it allows to call the api in post on the road 'http://localhost:3000/api/login', returning this.http.post will return an Observable that can be subscribed to receive the data in the form. return this.http.post(this.urlApi + 'login', data); } }
Now that we have our service which is reusable, don’t forget to import it in our form.component.ts to be able to call it.
Now it’s time to create the submission function.
import { Component, OnInit } from '@angular/core'; import { FormBuilder } from '@angular/forms'; import { LoginService } from '../services/login-service.service' @Component({ selector: 'app-login-form', templateUrl: './login-form.component.html', styleUrls: ['./login-form.component.scss'] }) export class LoginFormComponent implements OnInit { email: String = ''; password: String = ''; loginForm; currentUser; // We call the loginService to use its login function. constructor(private formBuilder: FormBuilder, private loginService: LoginService) { this.loginForm = this.formBuilder.group({ email: '', password: '' }); } ngOnInit(): void {} // Submit the form submit(){ // We create a data object with the fields of the completed form let data = { email: this.email, password: this.password } // We call the login service on the login method with the object data // The login service will send the HTTP request as a post to the server with the user's data. // We apply the subscribe method, which will listen to the returned observable. // The first function (value) is the return of the value, there is also the second (err) which allows to manage the error and the third () => {} which allows to define code when the subscriber is finished. this.loginService.login(data).subscribe( (value) => { this.loginService.currentUser = value this.loginService.token = value.token, this.currentUser = value localStorage.setItem('token', value.token) }, (err) => console.log(err) ) } }
If you are not familiar with the Observables you can go to the official Angular documentation which will explain it to you.
Now that we have our form built, a service that queries the server, and a subscriber that returns the data from the server, we can now work on the server itself.
ExpressJS server
As for the Angular front, I’m going to get to the heart of the matter right away, if you need to know more about ExpressJS, go to the site directly.
To make our authentication work we need the mysql library and the JWT library to generate a token. I let you install them to continue.
Cross Origin requests can also be annoying, install CORS
MySQL database service
Here is the DB service to put in a separate file to call the database easily.
var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '', database : 'angular-express' }); connection.connect(function(err) { if (err) throw err; }); module.exports = connection;
Replace with your data.
The server
const express = require('express') // Allow Cross Origin const cors = require("cors"); const app = express() const port = 3000 // Allows to convert data received in HTTP into readable variable const bodyParser = require('body-parser'); //Allows you to use the database, change according to you var db = require('./database'); // To use JWT var jwt = require('jsonwebtoken'); // We convert the data app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); // We allow cross origin (Angular in port 4200 and api in 3000 ...) app.use(cors()); // Our login route app.post('/api/login', (req, res) => { // We retrieve the variables sent by our form from the login service. let { email, password } = req.body; // We instantiate a variable that greets the user let user; // We make our request to verify that the user exists under the email sent. db.query('SELECT * FROM user WHERE email = ?', [email], function(err, result) { if (err) throw err; // We store our user in our variable user = result[0] // Small parenthesis, for this tuto the mdp are not hashed in the base, it is not the subject, then we compare without decrypting the passwords if(user.password == password){ // If all the information is ok then we generate the jwt with the user's data (we avoid to put the password it's not secured), and we add a 'secret' keyword, to change according to your wishes, it must be secret precisely, we define the jwt valid one hour var token = jwt.sign({ id: user.id, email: user.email, name: user.name }, 'secret', { expiresIn: '1h' }); // We give the token to the user and we return the user user.token = token res.send(user) } else { // Otherwise the user is warned that no one is found. res.send(["User don't find"]) } }); }) // The server listen app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) })
All is good, for my part here are my test data.
My form (a bit stylized) :
To check the status of the request returned by your server, open the developer console of your browser (Ctrl SHIFT + I under chrome) and go to network.
Submit the form and you will get a preview of the request sent.
We see to which URL the request was sent, the method, and the status. Go to the Preview tab to see the data returned by ExpressJS.

We have received our user’s data with this famous JWT token, which we can decrypt on the JWT.io site.
Hence the interest of not storing the password in the JWT! We also have the iat data for when the token was created and exp for its expiration.
Our form is now able to receive the user who wants to log in, give him a token that proves that the user has entered his credentials, and the login service has stored all this in memory to be reused wherever we want, now it’s time to see the secure api routes via the token.
Secure routes via JWT on ExpressJS
Let’s take this road as an example:
app.get('/api/dataNeedLogged', (req, res) => { res.send({ message: "You are logged with JWT you can see the data"}) })
It sends us a simple message but the a is not the subject, it has nothing different from the login route for the moment, we will secure it. It is necessary to set up a JWT authentication middleware. If I had to explain roughly what the Middleware is, it’s like a function that launches before your main function, see example :
//We import the middleware let authMiddleware = require('./auth_jwt.middleware') //We add our middleware BEFORE the main function of our route app.get('/api/dataNeedLogged', authMiddleware, (req, res) => { res.send({ message: "You are logged with JWT you can see the data"}) })
Middleware content :
//Dependancies imports const jwt = require("jsonwebtoken") const db = require('./database') //Here is the function that will be launched before the main function of the route //It has the same parameters as our route to an EXCEPTION, the NEXT parameter, it is mandatory and allows you to tell the MIDDLEWARE ok you can go to the main function const auth = (req, res, next) => { try { // We retrieve the token of the HTTP request const token = req.header('Authorization').replace("Bearer ", "") // Decode the token with the "secret" key, replace with your secret key! const decoded = jwt.verify(token, "secret") //Thanks to the decoded token we have the id of the user, so we can retrieve it. //and judge whether or not he or she has the right of access db.query('SELECT * FROM user WHERE id = ?', [decoded.id], function (err, result) { if (err) throw err; user = result[0] //If no user is found, error 401 is issued. if (!user) { throw new Error() } req.token = token req.user = user //We move on to the main query next() }); } catch (e) { res.status(401).send({ error: 'Please authenticate.' }) } } //We export the function to include it before our route function. module.exports = auth;
Angular must now send us the authentication token for each request, this is managed with an interceptor.
Angular, add the JWT token to the HTTP request
Here is the interceptor class that will allow us to add the token to our HTTP requests:
import {Injectable} from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor() {} //Before sending an HTTP request, the interceptor will add the token to the authentication. intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { //Token retrieval const token = localStorage.getItem('token'); //We clone the query by adding a headers Authorization with the Bearer string followed by the token req = req.clone({ setHeaders: { 'Authorization': `Bearer ${token}` }, }); return next.handle(req); } }
In order for it to intercept all the requests it is necessary to go to app.module.ts and add the following provider:
//We import HTTP_INTERCEPTORS import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; //and our interceptor import { AuthInterceptor } from './interceptor/auth.interceptor' ... ... ... //And we tell Angular to use it... providers: [ {provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true}, ],
Now our requests from Angular are ready to communicate with the secure routes of the ExpressJS API, the tutorial is now over.
Thanks for reading, feel free to share!