How to Create Token-Based JWT Authentication in Laravel 9 Angular

Throughout this Laravel 9 Angular comprehensive tutorial, you will learn how to create JWT (JSON Web Token) secure authentication in Laravel Angular app using REST API.

Security is the biggest concern in the web development domain; one to enhance the safety or refrain the oppressive users from accessing the app is to implement token-based authentication.

In this Laravel Angular JWT Auth example, we will learn to register a user and securely log in to the application with a JWT token.

Apart from simple user auth, you will be taught how to configure CORS middleware within Laravel, manage server-side validation, create JSON web token to manifest profound security and that too from scratch.

Regardless of multiple front-end frameworks exists in the web development realm still Angular is one of the best TypeScript-based open-source web application framework developed by Google.

Earlier its is known to be AngularJS or Angular 1; this tutorial focuses on the Angular 2+ version.

You will also be seeing how to use Auth REST API in Laravel Angular app to authenticate; also, database interaction will be covered.

Create Laravel/Angular App

Create the main project folder; name it something like this:

mkdir laravel-angular-jwt-auth

Your project must contain frontend and backend folders altogether:

- laravel-angular-jwt-auth
--- backend
--- frontend

Create Laravel JWT Auth REST API

In this step you have to clone the Laravel JWT Auth REST API project, It will lower the time for building auth REST API:

Use below command to head over to backend directory:

cd backend

Next, run the command to clone the repo:

git clone https://github.com/remotestack377/LaravelJWTAuthenticationExample.git

Unzip the laravel app and keep all the files inside the backend folder.

While staying in the backend folder, execute the following commands respectively:

composer install
cp .env.example .env
php artisan key:generate
php artisan migrate
php artisan serve

Here are the auth APIs that you need for Laravel Angular authentication:

Methods Endpoints
POST /api/auth/signup
POST /api/auth/signin
GET /api/auth/user
POST /api/auth/token-refresh
POST /api/auth/signout

Setting Up CORS Middleware

Next you have to set up the CORS middleware in the Laravel application:

php artisan make:middleware CORS

Add following code in app/Http/Middleware/CORS.php file:

<?php

namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Closure;

class CORS {
    
    public function handle(Request $request, Closure $next) {
        header('Acess-Control-Allow-Origin: *');
        header('Acess-Control-Allow-Origin: Content-type, X-Auth-Token, Authorization, Origin');
        return $next($request);
    }

}

Define CORS in $routeMiddleware within app/Http/Kernel.php configuration file:

protected $routeMiddleware = [
    ...
    ...
    ...
    'guest' => \App\Http\Middleware\CORS::class,
];

After adding the CORS middleware in your laravel application start the development server again:

php artisan serve

Setting Up Angular in Laravel

In this step you have to install Angular application in frontend folder:

ng new frontend && cd frontend

Next, you have to generate components for handling JWT authentication process:

ng g c components/login

ng g c components/register

ng g c components/profile

Install equally important add Bootstrap CSS path to angular.json file:

"styles": [
      "node_modules/bootstrap/dist/css/bootstrap.min.css",
      "src/styles.scss"
]

Next, you have to import and inject HttpClient API in app.module.ts it will let you make HTTP requests through Laravel REST auth API:

...
...
...
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [
    HttpClientModule
   ]
})

...
...

Create Routes and Enable Navigation

To create routes you have to import and assign components to their respective route, so open and update the following code in app-routing.module.ts file:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { LoginComponent } from './components/login/login.component';
import { RegisterComponent } from './components/register/register.component';
import { ProfileComponent } from './components/profile/profile.component';

const routes: Routes = [
  { path: '', redirectTo: '/signin', pathMatch: 'full' },
  { path: 'signin', component: LoginComponent },
  { path: 'signup', component: RegisterComponent },
  { path: 'user-profile', component: ProfileComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})

export class AppRoutingModule { }

Add Angular Form Services

In this step, you have to import ReactiveFormsModule and FormsModule APIs and inject them in the imports array in app.module.ts:

...
...
import { ReactiveFormsModule, FormsModule } from '@angular/forms';

@NgModule({
  imports: [
    ReactiveFormsModule,
    FormsModule
  ],
})
...
...

Run angular application with below command:

ng serve --open

Create Angular Service

You will have to create angular service to define the methods which will be useful for making HTTP requests and consuming Laravel REST API:

ng g s shared/jwt

Open shared/jwt.service.ts file and insert the under-mentioned code.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

export class User {
  name: String;
  email: String;
  password: String;
  password_confirmation: String
}

@Injectable({
  providedIn: 'root'
})

export class JwtService {

  constructor(private http: HttpClient) { }

  signUp(user: User): Observable<any> {
    return this.http.post('http://127.0.0.1:8000/api/auth/signup', user);
  }

  logIn(user: User): Observable<any> {
    return this.http.post<any>('http://127.0.0.1:8000/api/auth/signin', user);
  }

  profile(): Observable<any> {
    return this.http.get('http://127.0.0.1:8000/api/auth/user');
  }

}

Create JWT Token Service

In this step you need to create a token service which will allow us create JWT token in local storage, validate the token for accessing the app, and also destroy the token for logout.

ng g s shared/tokenAuth

Update below code in shared/token-auth.service.ts:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})

export class TokenAuthService {

  private tokenIssuer = {
    login: 'http://127.0.0.1:8000/api/auth/signin',
    register: 'http://127.0.0.1:8000/api/auth/signup'
  }

  constructor() { }

  setTokenStorage(token){
    localStorage.setItem('auth_token', token);
  }

  getJwtToken(){
    return localStorage.getItem('auth_token');
  }

  // Validate token
  validateToken(){
     const token = this.getJwtToken();

     if(token){
       const payload = this.payload(token);
       if(payload){
         return Object.values(this.tokenIssuer).indexOf(payload.iss) > -1 ? true : false;
       }
     } else {
        return false;
     }
  }

  payload(token) {
    const jwtPayload = token.split('.')[1];
    return JSON.parse(atob(jwtPayload));
  }

  // User state
  isSignedin() {
    return this.validateToken();
  }

  // Destroy token
  destroyToken(){
    localStorage.removeItem('auth_token');
  }

}

Configure Authentication State

In this step, we have to create a auth state that we will circulate in every angular component to let about current user state with the help of angular service:

ng g s shared/authentication-state

Update code in shared/authentication-state.service.ts file:

import { Injectable } from '@angular/core';
import { TokenAuthService } from '../shared/token-auth.service';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';

@Injectable({
  providedIn: 'root'
})

export class AuthenticationStateService {

  private userCurrentState = new BehaviorSubject<boolean>(this.tokenAuthService.isSignedin());
  userAuthState = this.userCurrentState.asObservable();

  constructor(
    public tokenAuthService: TokenAuthService
  ) { }

  setAuthState(value: boolean) {
    this.userCurrentState.next(value);
  }

}

Create Header with HttpInterceptor

In this step we have to set the token in Header, it will be done by HttpInterceptor class:

You need to create the shared/auth-header.interceptor.ts file and update the following code:

import { Injectable } from "@angular/core";
import { HttpInterceptor, HttpRequest, HttpHandler } from "@angular/common/http";
import { TokenAuthService } from "../shared/token-auth.service";

@Injectable()

export class AuthHeaderInterceptor implements HttpInterceptor {
    
    constructor(private tokenAuthService: TokenAuthService) { }

    intercept(req: HttpRequest<any>, next: HttpHandler) {
        const jwtHeaderToken = this.tokenAuthService.getJwtToken();
        req = req.clone({
            setHeaders: {
                Authorization: "Bearer " + jwtHeaderToken
            }
        });
        return next.handle(req);
    }
}

Update the app.module.ts file:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginComponent } from './components/login/login.component';
import { RegisterComponent } from './components/register/register.component';
import { ProfileComponent } from './components/profile/profile.component';

import { ReactiveFormsModule, FormsModule } from '@angular/forms';

import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthHeaderInterceptor } from './shared/auth-header.interceptor';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent,
    RegisterComponent,
    ProfileComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    ReactiveFormsModule,
    FormsModule    
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthHeaderInterceptor,
      multi: true
    }    
  ],
  bootstrap: [AppComponent]
})

export class AppModule { }

Create Angular User Registration

Now that we have to configure the register component, it will allow you to register a user with the help of Laravel REST API in angular application.

So, update the register.component.ts file:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { FormBuilder, FormGroup } from "@angular/forms";
import { JwtService } from './../../shared/jwt.service';

@Component({
  selector: 'app-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.scss']
})

export class RegisterComponent implements OnInit {

  signupForm: FormGroup;
  err = null;

  constructor(
    public fb: FormBuilder,
    public router: Router,
    public jwtService: JwtService
  ) {
    this.signupForm = this.fb.group({
      name: [''],
      email: [''],
      password: [''],
      password_confirmation: ['']
    })
  }

  ngOnInit() { }

  onSubmit() {
    this.jwtService.signUp(this.signupForm.value).subscribe(
      res => {
        console.log(res)
      },
      error => {
        this.err = error.error;
      },
      () => {
        this.signupForm.reset()
        this.router.navigate(['signin']);
      }
    )
  }

}

Open and update the below code in register.component.html:

<form [formGroup]="signupForm" (ngSubmit)="onSubmit()">
  <h2 class="mb-3 text-center">Signup</h2>

  <div class="form-group">
    <label>Name</label>
    <input type="text" class="form-control" formControlName="name">

    <div *ngIf="err?.name" class="alert alert-danger mt-3">
      {{ err?.name }}
    </div>
  </div>

  <div class="form-group">
    <label>Email</label>
    <input type="email" class="form-control" formControlName="email">

    <div *ngIf="err?.email" class="alert alert-danger mt-3">
      {{ err?.email }}
    </div>
  </div>

  <div class="form-group">
    <label>Password</label>
    <input type="password" class="form-control" formControlName="password">

    <div *ngIf="err?.password" class="alert alert-danger mt-3">
      {{ err?.password }}
    </div>
  </div>

  <div class="form-group">
    <label>Confirm Password</label>
    <input type="password" class="form-control" formControlName="password_confirmation">

    <div *ngIf="err?.password_confirmation" class="alert alert-danger mt-3">
      {{ err?.password_confirmation }}
    </div>
  </div>

  <button type="submit" class="btn btn-success">Signup</button>
</form>

Signin Component

Open and update below code in login.component.ts:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { FormBuilder, FormGroup } from "@angular/forms";

import { JwtService } from './../../shared/jwt.service';
import { TokenAuthService } from '../../shared/token-auth.service';
import { AuthenticationStateService } from '../../shared/authentication-state.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})

export class LoginComponent implements OnInit {

  signinForm: FormGroup;
  err = null;

  constructor(
    public router: Router,
    public fb: FormBuilder,
    public jwtService: JwtService,
    private tokenAuthService: TokenAuthService,
    private authenticationStateService: AuthenticationStateService,
  ) {
    this.signinForm = this.fb.group({
      email: [],
      password: []
    })
  }

  ngOnInit() { }

  onSubmit() {
      this.jwtService.logIn(this.signinForm.value).subscribe(
        res => {
          this.tokenStorage(res);
        },
        error => {
          this.err = error.error;
        },() => {
          this.authenticationStateService.setAuthState(true);
          this.signinForm.reset()
          this.router.navigate(['user-profile']);
        }
      );
  }

  tokenStorage(jwt){
    this.tokenAuthService.setTokenStorage(jwt.access_token);
  }

}

Open and update following code in login.component.html:

<form [formGroup]="signinForm" (ngSubmit)="onSubmit()">
  <h2 class="h3 mb-3">Login</h2>

  <div class="form-group">
    <label>Email address</label>
    <input type="email" class="form-control" formControlName="email">

    <div *ngIf="err?.email" class="alert alert-danger mt-3">
      {{ err?.email }}
    </div>

    <div *ngIf="err?.password" class="alert alert-danger mt-3">
      {{ err?.password }}
    </div>
  </div>

  <div class="form-group">
    <label>Password</label>
    <input type="password" class="form-control" formControlName="password">

    <div *ngIf="err?.error" class="alert alert-danger mt-3">
      {{ err?.error }}
    </div>
  </div>

  <button type="submit" class="btn btn-success">Signin</button>
</form>

Create User Profile Component

In this step, you will learn how to create user profile functionality, so go ahead and add the following code in profile.component.ts file:

import { Component } from '@angular/core';
import { JwtService } from './../../shared/jwt.service';

export class User {
  name: String;
  email: String;
}

@Component({
  selector: 'app-profile',
  templateUrl: './profile.component.html',
  styleUrls: ['./profile.component.scss']
})

export class ProfileComponent {

  user: User;

  constructor(
    public jwtService: JwtService
  ) {
    this.jwtService.profile().subscribe((res:any) => {
      this.user = res;
    })
  }

}

Open and update profile.component.html file:

<div class="container">
  <h2>Name: {{user?.name}}</h2>
  <p>Email: {{user?.email}}</p>
</div>

Angular Logout Component

In this step you will create logout feature, so go ahead and update the app.component.ts file:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { TokenAuthService } from './shared/token-auth.service';
import { AuthenticationStateService } from './shared/authentication-state.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent {
  
  isLoggedin: boolean;

  constructor(
    public router: Router,
    private tokenAuthService: TokenAuthService,
    public authenticationStateService: AuthenticationStateService
  ) {
  }

  ngOnInit() {
    this.authenticationStateService.userAuthState.subscribe(res => {
        this.isLoggedin = res;
    });
  }

  logOut() {
    this.authenticationStateService.setAuthState(false);
    this.tokenAuthService.destroyToken();
    this.router.navigate(['signin']);
  }  

}

Open and update following code in app.component.html, it will enable the navigation and also display the button which will log out from the application:

<div class="container">
  <h2>Laravel Angular JWT Authenticaiton Examlpe</h2>
  <nav>
    <a routerLink="/user-profile" *ngIf="isLoggedin">Profile</a>
    <a *ngIf="!isLoggedin" routerLink="/signin">Log in</a>
    <a routerLink="/signup">Sign up</a>
  </nav>

  <button class="btn btn-danger" (click)="logOut()" *ngIf="isLoggedin">Sign-out</button>
</div>

<router-outlet></router-outlet>

Run Laravel Server

First you have to get inside the laravel project and start the development server, so use the below commands simultaneously:

cd backend && php artisan serve

Run Angular Server

Open another terminal, move inside the angular project and start the angular development server, so use the below commands simultaneously:

cd frontend && ng serve --open

If anyhow you get following error after signup:

Jwt Authentication error Argument 3 passed to Lcobucci\JWT\Signer\Hmac::doVerify()

So, get inside the laravel backend and run the following commands one after another:

php artisan key:generate
php artisan jwt:secret
php artisan cache:clear
php artisan config:clear

Summary

This tutorial is over; in this tutorial, you learned how to create laravel angular application for handling token-based JWT authentication from scratch.

I hope this tutorial will help you enhance your full-stack web development skills.

Download final project