DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Secure Your API With JWT: Kong OpenID Connect
  • Securing REST APIs With Nest.js: A Step-by-Step Guide
  • Navigating the API Seas: A Product Manager's Guide to Authentication
  • Spring OAuth Server: Token Claim Customization

Trending

  • Building Resilient Networks: Limiting the Risk and Scope of Cyber Attacks
  • Building Resilient Identity Systems: Lessons from Securing Billions of Authentication Requests
  • Unlocking Data with Language: Real-World Applications of Text-to-SQL Interfaces
  • Mastering Fluent Bit: Installing and Configuring Fluent Bit on Kubernetes (Part 3)
  1. DZone
  2. Coding
  3. Frameworks
  4. JWT Token Authentication in Angular 14 and .NET Core 6 Web API

JWT Token Authentication in Angular 14 and .NET Core 6 Web API

This article discusses all JWT Authentication in Angular 14 step-by-step and how to store tokens in local storage and use them inside the product application.

By 
Jaydeep Patil user avatar
Jaydeep Patil
·
Aug. 17, 23 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
9.3K Views

Join the DZone community and get the full member experience.

Join For Free

In this article, we will discuss JWT Authentication in Angular 14 step-by-step.

If you want to learn the basics and details of the JWT Token, then check out this article. 

Also, I recommend you read this article, where I explain how to set up a backend server application using.NET Core 6 before starting. 

Introduction

  • JSON Web Token is the open standard (RFC 7519) self-contained way that will be used to transmit the data securely over the different environments as a JSON Object.
  • RFC (Request for Comment) is the shortened form of Remote Function Call and Formal Document from the Internet Engineering Task Force. RFC 7519: JSON Web Token (JWT) May 2015 Copyright Notice Copyright: 2015 IETF Trust and the persons identified as the document authors All rights reserved.
  • JWT is the trusted way of authentication because it is digitally signed and secret using the HMAC algorithm, or sometimes using a public/private key using RSA.
  • Basically, HMAC stands for Hashed-based Message Authentication Code, it uses some great cryptographic hashing techniques that provide us with great security.
  • Also, the JWT is part of great Authentication and Authorization Frameworks like OAuth and OpenID, which will provide a great mechanism to transfer data securely.

Create Angular Application

Step 1:

Create an Angular Application using the following command:

ng new WebAPP 

Step 2:

We use Bootstrap in this application. So, use the following command to install Bootstrap:

npm install bootstrap 

Next, add the bootstrap script inside the angular.json file inside the scripts and styles section 

JSON
 
"styles": [
             "src/styles.css",
             "./node_modules/bootstrap/dist/css/bootstrap.min.css"
           ],
           "scripts": [
             "./node_modules/bootstrap/dist/js/bootstrap.min.js"
           ]


Step 3:

Install the Toaster module for pop-ups and notifications.

npm install ngx-toastr –save 

Then, add the toaster in the styles section inside the angular.json file

JSON
 
"styles": [
             "src/styles.css",
             "node_modules/ngx-toastr/toastr.css",
             "./node_modules/bootstrap/dist/css/bootstrap.min.css"
           ],
           "scripts": [
             "./node_modules/bootstrap/dist/js/bootstrap.min.js"
           ]


Step 4:

Application structure:

application structure

Step 5:

Create a config folder inside assets, create a config.json file inside that as shown below, and put the backend application API URL inside that.

JSON
 
{
    "apiServer": {
      "url": "https://localhost:7299",
      "version": "v1"
    }
}


Step 6:

Create Auth Guard inside the guard’s folder.

TypeScript
 
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { JwtHelperService } from '@auth0/angular-jwt';
@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private jwtHelper: JwtHelperService, private router: Router) {
  }
  canActivate() {
    //get the jwt token which are present in the local storage
    const token = localStorage.getItem("jwt");
    //Check if the token is expired or not and if token is expired then redirect to login page and return false
    if (token && !this.jwtHelper.isTokenExpired(token)){
      return true;
    }
    this.router.navigate(["login"]);
    return false;
  }
}


So, here you can see we take the JWT token from the local storage and later on check if the token is expired or not. If the token is expired, then it will redirect to login and return false.

Step 7:

Open the App Component files and add the following code inside them:

app.component.ts

TypeScript
 
import { Component } from '@angular/core';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'ProductWebAPP';
}


app.component.html 

HTML
 
<router-outlet></router-outlet>


Step 8:

Create a Model folder inside the app directory and create a Product class inside that:

TypeScript
 
export class Products {
    productId: any;
    productName?: string;
    productCost?: number;
    productDescription?: string;
    productStock?: number;
  }


Step 9:

Create a Homepage component.

homepage.component.ts

TypeScript
 
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { JwtHelperService } from '@auth0/angular-jwt';
@Component({
  selector: 'app-homepage',
  templateUrl: './homepage.component.html',
  styleUrls: ['./homepage.component.css']
})
export class HomepageComponent  {
  constructor(private jwtHelper: JwtHelperService, private router: Router) {
  }
  isUserAuthenticated() {
    const token = localStorage.getItem("jwt");
    if (token && !this.jwtHelper.isTokenExpired(token)) {
      return true;
    }
    else {
      return false;
    }
  }
  public logOut = () => {
    localStorage.removeItem("jwt");
  }
}


homepage.component.html 

HTML
 
<nav class="navbar navbar-expand-lg navbar navbar-dark bg-dark">
  <a class="navbar-brand" href="#">Product Application</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarText">
    <ul class="navbar-nav mr-auto">
      <li *ngIf="isUserAuthenticated()" class="nav-item">
        <a class="nav-link" routerLink="/product">Products</a>
      </li>
      <li *ngIf="isUserAuthenticated()" class="nav-item">
        <a class="nav-link" (click)="logOut()">Logout</a>
      </li>
    </ul>
  </div>
</nav>
<div *ngIf="!isUserAuthenticated()">
  <login></login>
</div>
<div *ngIf="isUserAuthenticated()" style="color:green;">
  <h2>
    Welcome to the Product Application
  </h2>
</div>


Step 10:

Create a Login Component.

login.component.ts

TypeScript
 
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Component } from '@angular/core';
import { Router } from "@angular/router";
import { NgForm } from '@angular/forms';
import configurl from '../../assets/config/config.json';
import { JwtHelperService } from '@auth0/angular-jwt';
import { ToastrService } from 'ngx-toastr';
@Component({
  selector: 'login',
  templateUrl: './login.component.html'
})
export class LoginComponent {
  invalidLogin?: boolean;
  url = configurl.apiServer.url + '/api/authentication/';
  constructor(private router: Router, private http: HttpClient,private jwtHelper : JwtHelperService,
    private toastr: ToastrService) { }
  public login = (form: NgForm) => {
    const credentials = JSON.stringify(form.value);
    this.http.post(this.url +"login", credentials, {
      headers: new HttpHeaders({
        "Content-Type": "application/json"
      })
    }).subscribe(response => {
      const token = (<any>response).token;
      localStorage.setItem("jwt", token);
      this.invalidLogin = false;
      this.toastr.success("Logged In successfully");
      this.router.navigate(["/product"]);
    }, err => {
      this.invalidLogin = true;
    });
  }
  isUserAuthenticated() {
    const token = localStorage.getItem("jwt");
    if (token && !this.jwtHelper.isTokenExpired(token)) {
      return true;
    }
    else {
      return false;
    }
  }
}


login.component.html 

HTML
 
<form class="form-signin" #loginForm="ngForm" (ngSubmit)="login(loginForm)">
    <div class="container-fluid">
        <h2 class="form-signin-heading">Login</h2>
        <div *ngIf="invalidLogin" class="alert alert-danger">Invalid username or password.</div>
        <br/>
        <label for="username" class="sr-only">Email address</label>
        <input type="email" id="username" name="username" ngModel class="form-control" placeholder="User Name" required autofocus>
        <br/>
        <label for="password" class="sr-only">Password</label>
        <input type="password" id="password" name="password" ngModel class="form-control" placeholder="Password" required>
        <br/>
        <button class="btn btn-lg btn-primary btn-block" type="submit">Login</button>
    </div>
</form>


Step 11:

Create Products Component.

products.component.ts

TypeScript
 
import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { Observable } from 'rxjs';
import { ProductsService } from '../products/products.service';
import { Products } from '../Models/Products';
import { Router } from '@angular/router';
import { JwtHelperService } from '@auth0/angular-jwt';
import { ToastrService } from 'ngx-toastr';
@Component({
  selector: 'app-product',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
  ProductList?: Observable<Products[]>;
  ProductList1?: Observable<Products[]>;
  productForm: any;
  massage = "";
  prodCategory = "";
  productId = 0;
  constructor(private formbulider: FormBuilder,
     private productService: ProductsService,private router: Router,
     private jwtHelper : JwtHelperService,private toastr: ToastrService) { }
  ngOnInit() {
    this.prodCategory = "0";
    this.productForm = this.formbulider.group({
      productName: ['', [Validators.required]],
      productCost: ['', [Validators.required]],
      productDescription: ['', [Validators.required]],
      productStock: ['', [Validators.required]]
    });
    this.getProductList();
  }
  getProductList() {
    this.ProductList1 = this.productService.getProductList();
    this.ProductList = this.ProductList1;
  }
  PostProduct(product: Products) {
    const product_Master = this.productForm.value;
    this.productService.postProductData(product_Master).subscribe(
      () => {
        this.getProductList();
        this.productForm.reset();
        this.toastr.success('Data Saved Successfully');
      }
    );
  }
  ProductDetailsToEdit(id: string) {
    this.productService.getProductDetailsById(id).subscribe(productResult => {
      this.productId = productResult.productId;
      this.productForm.controls['productName'].setValue(productResult.productName);
      this.productForm.controls['productCost'].setValue(productResult.productCost);
      this.productForm.controls['productDescription'].setValue(productResult.productDescription);
      this.productForm.controls['productStock'].setValue(productResult.productStock);
    });
  }
  UpdateProduct(product: Products) {
    product.productId = this.productId;
    const product_Master = this.productForm.value;
    this.productService.updateProduct(product_Master).subscribe(() => {
      this.toastr.success('Data Updated Successfully');
      this.productForm.reset();
      this.getProductList();
    });
  }
  DeleteProduct(id: number) {
    if (confirm('Do you want to delete this product?')) {
      this.productService.deleteProductById(id).subscribe(() => {
        this.toastr.success('Data Deleted Successfully');
        this.getProductList();
      });
    }
  }
  Clear(product: Products){
    this.productForm.reset();
  }
  public logOut = () => {
    localStorage.removeItem("jwt");
    this.router.navigate(["/"]);
  }
  isUserAuthenticated() {
    const token = localStorage.getItem("jwt");
    if (token && !this.jwtHelper.isTokenExpired(token)) {
      return true;
    }
    else {
      return false;
    }
  }
}


products.component.html 

HTML
 
<nav class="navbar navbar-expand-lg navbar navbar-dark bg-dark">
  <a class="navbar-brand" href="#">Product Application</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarText">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" routerLink="/">Home</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" (click)="logOut()">Logout</a>
      </li>
      <li *ngIf="!isUserAuthenticated()" class="nav-item active">
        <a class="nav-link" routerLink="/product">Products</a>
      </li>
    </ul>
  </div>
</nav>
<form class="form-horizontal" [formGroup]="productForm">
    <h1 style="text-align: center;">Welcome to Angular 14 CRUD with .NET 6 Web API</h1>
    <div>
    <div class="form-group">
      <label class="control-label col-sm-2" for="pwd">Product Name:</label>
      <div class="col-sm-10">
        <input type="text" class="form-control" id="txtProductName" formControlName="productName"
          placeholder="Name of Product">
      </div>
    </div>
    <br />
    <div class="form-group">
      <label class="control-label col-sm-2" for="pwd">Product Description :</label>
      <div class="col-sm-10">
        <input type="text" class="form-control" id="txtProductDescription" formControlName="productDescription"
          placeholder="Product Description">
      </div>
    </div>
    <br />
    <div class="form-group">
      <label class="control-label col-sm-2" for="pwd">Product Cost:</label>
      <div class="col-sm-10">
        <input type="text" class="form-control" id="txtProductCost" formControlName="productCost" placeholder="Cost of Product">
      </div>
    </div>
    <br />
    <div class="form-group">
      <label class="control-label col-sm-2" for="pwd">Product Stock Available :</label>
      <div class="col-sm-10">
        <input type="text" class="form-control" id="txtStock" formControlName="productStock" placeholder="Stock Available">
      </div>
    </div>
    <br />
     <div class="form-group">
      <div class="container">
        <div class="row">
          <div class="col-sm">
            <button type="submit" class="btn btn-primary" (click)="PostProduct(productForm.value)">Submit</button>
          </div>
          <div class="col-sm">
            <button type="submit" class="btn btn-primary" (click)="UpdateProduct(productForm.value)">Update</button>
          </div>
          <div class="col-sm">
            <button type="submit" class="btn btn-primary" (click)="Clear(productForm.value)">Clear</button>
          </div>
        </div>
      </div>
    <br />
    </div>
    <div>
      <div class="alert alert-success" style="text-align: center;"><b>Product List</b></div>
      <div class="table-responsive" style="text-align: center;">
        <table class="table table-striped">
          <thead>
          <tr>
            <th scope="col">#</th>
            <th scope="col">Product Name</th>
            <th scope="col">Description</th>
            <th scope="col">Cost</th>
            <th scope="col">Stock</th>
            <th scope="col">Action</th>
          </tr>
        </thead>
        <tbody>
          <tr *ngFor="let prd of ProductList | async; index as i">
            <th scope="row">{{ i + 1 }}</th>
            <td>{{prd.productName}}</td>
            <td>{{prd.productDescription}}</td>
            <td>{{prd.productCost}}</td>
            <td>{{prd.productStock}}</td>
            <td><button type="button" class="btn1" matTooltip="Click Edit Button" (click)='ProductDetailsToEdit(prd.productId)'>Edit</button>
              |
              <button type="button" class="btn1" matTooltip="Click Delete Button" (click)="DeleteProduct(prd.productId)">Delete</button>
            </td>
          </tr>
        </tbody>
        </table>
      </div>
    </div>
    </div>
  </form>


Step 12:

Next, create a Product Service to send all our requests and fetch the data from the backend application:

TypeScript
 
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Products } from '../Models/Products';
import configurl from '../../assets/config/config.json'
@Injectable({
  providedIn: 'root'
})
export class ProductsService {
  url = configurl.apiServer.url + '/api/product/';
  constructor(private http: HttpClient) { }
  getProductList(): Observable<Products[]> {
    return this.http.get<Products[]>(this.url + 'ProductsList');
  }
  postProductData(productData: Products): Observable<Products> {
    const httpHeaders = { headers:new HttpHeaders({'Content-Type': 'application/json'}) };
    return this.http.post<Products>(this.url + 'CreateProduct', productData, httpHeaders);
  }
  updateProduct(product: Products): Observable<Products> {
    const httpHeaders = { headers:new HttpHeaders({'Content-Type': 'application/json'}) };
    return this.http.post<Products>(this.url + 'UpdateProduct?id=' + product.productId, product, httpHeaders);
  }
  deleteProductById(id: number): Observable<number> {
    return this.http.post<number>(this.url + 'DeleteProduct?id=' + id, null);
  }
  getProductDetailsById(id: string): Observable<Products> {
    return this.http.get<Products>(this.url + 'ProductDetail?id=' + id);
  }
}
TypeScript
 
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ProductsComponent } from './products/products.component';
import {HttpClientModule} from '@angular/common/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule, Routes } from '@angular/router';
import { JwtModule } from "@auth0/angular-jwt";
import { AuthGuard } from './guards/auth-guard.service';
import { HomepageComponent } from './homepage/homepage.component';
import { LoginComponent } from './login/login.component';
import { ToastrModule } from 'ngx-toastr';
//all components routes
const routes: Routes = [
  { path: '', component: HomepageComponent },
  { path: 'product', component: ProductsComponent, canActivate: [AuthGuard] },
  { path: 'login', component: LoginComponent },
];
//function is use to get jwt token from local storage
export function tokenGetter() {
  return localStorage.getItem("jwt");
}
@NgModule({
  declarations: [
    AppComponent,
    ProductsComponent,
    HomepageComponent,
    LoginComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    FormsModule,
    ReactiveFormsModule,
    RouterModule.forRoot(routes),
    JwtModule.forRoot({
      config: {
        tokenGetter: tokenGetter,
        allowedDomains: ["localhost:7299"],
        disallowedRoutes: []
      }
  }),
  ToastrModule.forRoot()
  ],
  providers: [AuthGuard],
  bootstrap: [AppComponent]
})
export class AppModule { }


Step 13:

Put the following code inside the app module:

TypeScript
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ProductsComponent } from './products/products.component';
import {HttpClientModule} from '@angular/common/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule, Routes } from '@angular/router';
import { JwtModule } from "@auth0/angular-jwt";
import { AuthGuard } from './guards/auth-guard.service';
import { HomepageComponent } from './homepage/homepage.component';
import { LoginComponent } from './login/login.component';
import { ToastrModule } from 'ngx-toastr';
//all components routes
const routes: Routes = [
  { path: '', component: HomepageComponent },
  { path: 'product', component: ProductsComponent, canActivate: [AuthGuard] },
  { path: 'login', component: LoginComponent },
];
//function is use to get jwt token from local storage
export function tokenGetter() {
  return localStorage.getItem("jwt");
}
@NgModule({
  declarations: [
    AppComponent,
    ProductsComponent,
    HomepageComponent,
    LoginComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    FormsModule,
    ReactiveFormsModule,
    RouterModule.forRoot(routes),
    JwtModule.forRoot({
      config: {
        tokenGetter: tokenGetter,
        allowedDomains: ["localhost:7299"],
        disallowedRoutes: []
      }
  }),
  ToastrModule.forRoot()
  ],
  providers: [AuthGuard],
  bootstrap: [AppComponent]
})
export class AppModule { }
view raw


So, here you can see, first, we put some routes and created one method to get the JWT token from local storage, and we also configured the JWT module and Auth Guard inside that.

Step 14:

Finally, run your application:

npm start


You will see the login page when running the application:

login page

After logging in, you will see the product page:

product page

Conclusion

So, we discussed all JWT Authentication in Angular 14 step-by-step and how to store tokens in local storage and use them inside the product application.

Web API AngularJS authentication JWT (JSON Web Token) Net (command)

Published at DZone with permission of Jaydeep Patil. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Secure Your API With JWT: Kong OpenID Connect
  • Securing REST APIs With Nest.js: A Step-by-Step Guide
  • Navigating the API Seas: A Product Manager's Guide to Authentication
  • Spring OAuth Server: Token Claim Customization

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!