Implement Laravel Authentication JSON Web Token-predicated REST API in Angular. In this tutorial, we will learn how to engender utilizer registration and authentication system and store the utilizer data in the MySQL database.
Generically, Token-Predicated Authentication provides secure authentication, we have developed JWT API in Laravel, and now in this tutorial, we will learn how to consolidate Laravel and Angular and engender a secure utilizer authentication system.
JWT token implements the robust solution to restrain unauthenticated utilizer access. Scilicet, I will endeavor to be more spontaneous and simple.
What we will be learning:
- Create a user with the name, email, and password values.
- Hash password to incorporate robustness in password.
- Setting up CORS middleware in laravel.
- Signin with email and password.
- Handle laravel server-side validation with angular.
- Generate JSON web token when the user logs in.
- Store and retrieve a JWT token of local storage.
- Set Bearer token in the Header using angular.
- Validate JWT payload.
- Manage user state globally with RxJS.
- Handle laravel auth API with angular service.
- Access user profile page, if authenticated successfully.
- Logout from the app by destroying the JWT token.
Prerequisite
To get along with this tutorial, we must have the following tools frameworks and databases knowledge.
- Node
- NPM
- Composer
- Laravel (PHP Framework)
- MAMP or XAMPP
- Angular
- IDE or Code Editor
Laravel 7 and Angular 10 Project Structure
Create the main project folder, and this folder includes the backend (Laravel API) and frontend (Angular) directories for handling our project.
Run command to create main project folder:
mkdir your_project_name
We can now manage backend and frontend of our application.
Clone Laravel 7 JWT Authentication Repo
I advise you to check our detailed tutorial on Securing Laravel Authentication API using JSON Web Token.
This tutorial requires you to clone the following repository inside the backend folder. Run the following command to clone the Laravel JWT authentication project from my GitHub repository.
git clone https://github.com/SinghDigamber/backend.git
Bash
Get inside the Laravel project folder:
cd backend
Execute following commands to install defined dependencies for node and composer for your laravel project.
# for node
npm install
# for compose
composer install
Run local PHP web server, you can use either MAMP or XAMPP.
Start the project:
php artisan serve
Use http://127.0.0.1:8000 as a base URL for User Registration and Login, Accessing User Profile, Refreshing the Token and Logging out from the app.
Method | Endpoint |
---|---|
POST | /api/auth/register |
POST | /api/auth/login |
GET | /api/auth/user-profile |
POST | /api/auth/refresh |
POST | /api/auth/logout |
Install and Configure Angular
Install a brand new Angular app using the below command:
ng new frontend && cd frontend
Create the following components to handle the user registration and authentication process.
ng g c components/signin
ng g c components/signup
ng g c components/user-profile
We are using the Bootstrap to design authentication form, you may skip this step if you want to use your custom CSS.
npm install bootstrap
Define the bootstrap CSS path inside the angular.json.
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.scss"
]
Start angular app on the browser.
ng serve --open
Adding up HttpClient
To handle the HTTP requests, import Http client module inside the app.module.ts file .
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
HttpClientModule
]
})
Insert Reactive Form Service
Reactive Form API provides spontaneous support while working with form data, and it is extremely useful to manage the form data filled by the user.
Before we start working with the form, Implementation of ReactiveFormsModule and FormsModule is compulsory, Import and register both the APIs in app.module.ts file.
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
@NgModule({
imports: [
ReactiveFormsModule,
FormsModule
],
})
Create CORS Middleware
We need to create CORS middleware, It allows to share resources between two different domain. Our backend is serving from on PORT:8000 and frontend running on PORT:4200.
Get inside the `backend`
folder and run the following command:
php artisan make:middleware CORS
Open app/Http/Middleware/CORS.php file and set the Acess-Control-Allow-Origin headers.
<?php
namespace App\Http\Middleware;
use Closure;
class CORS {
public function handle($request, Closure $next) {
header('Acess-Control-Allow-Origin: *');
header('Acess-Control-Allow-Origin: Content-type, X-Auth-Token, Authorization, Origin');
return $next($request);
}
}
Open app/Http/Kernel.php file and add the define the ‘guest’ CORS middleware inside the $routeMiddleware
array.
protected $routeMiddleware = [
...
'guest' => \App\Http\Middleware\CORS::class,
];
Now, restart the php server.
php artisan serve
Consume Laravel REST API with Angular Service
We will create Angular service to consume Laravel authentication API that we protected using JSON Web Token.
Execute command to generate Angular service file.
ng g s shared/auth
Open shared/auth.service.ts file and insert the under-mentioned code.
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
// User interface
export class User {
name: String;
email: String;
password: String;
password_confirmation: String
}
@Injectable({
providedIn: 'root'
})
export class AuthService {
constructor(private http: HttpClient) { }
// User registration
register(user: User): Observable<any> {
return this.http.post('http://127.0.0.1:8000/api/auth/register', user);
}
// Login
signin(user: User): Observable<any> {
return this.http.post<any>('http://127.0.0.1:8000/api/auth/login', user);
}
// Access user profile
profileUser(): Observable<any> {
return this.http.get('http://127.0.0.1:8000/api/auth/user-profile');
}
}
The User Interface class maps the incoming and outing data with API data. To handle Laravel API, spontaneously use HttpClient service.
Validate & Configure Laravel JWT Token in Angular
In this step, we will cover up the following tasks:
- Store the access token in local storage when a user logs in.
- Construct a function to retrieve the token from local storage.
- Verify the JWT token by decoding the payload and validating the issuer property of JWT token.
- Allow authorization based on the valid token.
- Remove token from local storage when the user signs out.
Run the command to generate service file:
ng g s shared/auth
Open shared/auth.service.ts file and insert the under-mentioned code.
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class TokenService {
private issuer = {
login: 'http://127.0.0.1:8000/api/auth/login',
register: 'http://127.0.0.1:8000/api/auth/register'
}
constructor() { }
handleData(token){
localStorage.setItem('auth_token', token);
}
getToken(){
return localStorage.getItem('auth_token');
}
// Verify the token
isValidToken(){
const token = this.getToken();
if(token){
const payload = this.payload(token);
if(payload){
return Object.values(this.issuer).indexOf(payload.iss) > -1 ? true : false;
}
} else {
return false;
}
}
payload(token) {
const jwtPayload = token.split('.')[1];
return JSON.parse(atob(jwtPayload));
}
// User state based on valid token
isLoggedIn() {
return this.isValidToken();
}
// Remove token
removeToken(){
localStorage.removeItem('auth_token');
}
}
Broadcast Authentication State to Multiple Components
Sometimes, you need to update the user state in multiple components based on logged in or out scenario.
Theoretically, RxJS can help us here. We will create another service that carries user state in the boolean form. When the user is logged in, it holds the true value and vice versa.
Execute command to create auth state service:
ng g s shared/auth-state
Open shared/auth-state.service.ts file and insert the under-mentioned code.
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { TokenService } from '../shared/token.service';
@Injectable({
providedIn: 'root'
})
export class AuthStateService {
private userState = new BehaviorSubject<boolean>(this.token.isLoggedIn());
userAuthState = this.userState.asObservable();
constructor(
public token: TokenService
) { }
setAuthState(value: boolean) {
this.userState.next(value);
}
}
Set JWT Token in Header with Angular HttpInterceptor
In general, when implementing token-based authentication, we need to set the token in the request header. It authenticates the request so that we can get the data securely.
To accomplish this task, we will be using Angular HttpInterceptor. It Intercepts and handles an HttpRequest or HttpResponse.
create the shared/auth.interceptor.ts inside the frontend folder and place the following code.
import { Injectable } from "@angular/core";
import { HttpInterceptor, HttpRequest, HttpHandler } from "@angular/common/http";
import { TokenService } from "../shared/token.service";
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private tokenService: TokenService) { }
intercept(req: HttpRequest<any>, next: HttpHandler) {
const accessToken = this.tokenService.getToken();
req = req.clone({
setHeaders: {
Authorization: "Bearer " + accessToken
}
});
return next.handle(req);
}
}
Incorporate the given code inside the app.module.ts file.
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './shared/auth.interceptor';
@NgModule({
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}
]
})
User Registration with Laravel and Angular
The given below code covers the following tasks in User registration module:
- Creating a form with Bootstrap.
- Consumption of an Auth API built with Laravel in Angular.
- Registering and Signing up a user and storing the user data spontaneously in the MySQL database.
- Getting the user data using React Forms in Angular.
- Handling the server-side validation in Angular extracted form the Laravel Auth API.
Open signup.component.ts file and append the following code.
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from './../../shared/auth.service';
import { FormBuilder, FormGroup } from "@angular/forms";
@Component({
selector: 'app-signup',
templateUrl: './signup.component.html',
styleUrls: ['./signup.component.scss']
})
export class SignupComponent implements OnInit {
registerForm: FormGroup;
errors = null;
constructor(
public router: Router,
public fb: FormBuilder,
public authService: AuthService
) {
this.registerForm = this.fb.group({
name: [''],
email: [''],
password: [''],
password_confirmation: ['']
})
}
ngOnInit() { }
onSubmit() {
this.authService.register(this.registerForm.value).subscribe(
result => {
console.log(result)
},
error => {
this.errors = error.error;
},
() => {
this.registerForm.reset()
this.router.navigate(['login']);
}
)
}
}
Open signup.component.html file and insert the following code.
<div class="auth-wrapper">
<form class="form-signin" [formGroup]="registerForm" (ngSubmit)="onSubmit()">
<h3 class="h3 mb-3 font-weight-normal text-center">Register User</h3>
<!-- Errors -->
<div *ngIf="errors?.name" class="alert alert-danger mt-3">
{{ errors?.name }}
</div>
<div *ngIf="errors?.email" class="alert alert-danger mt-3">
{{ errors?.email }}
</div>
<div *ngIf="errors?.password" class="alert alert-danger mt-3">
{{ errors?.password }}
</div>
<div *ngIf="errors?.password_confirmation" class="alert alert-danger mt-3">
{{ errors?.password_confirmation }}
</div>
<!-- Signup form -->
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" formControlName="name">
</div>
<div class="form-group">
<label>Email address</label>
<input type="email" class="form-control" formControlName="email">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" formControlName="password">
</div>
<div class="form-group">
<label>Confirm Password</label>
<input type="password" class="form-control" formControlName="password_confirmation">
</div>
<button type="submit" class="btn btn-block btn-primary">Register User</button>
</form>
</div>
Token Based Secure Login in Angular and Laravel
In this step, we will cover up the following tasks:
- Log in to the application using correct credentials
- Set the authentication state through auth state service, which hides and shows specific elements based on user state.
- Set Bearer token in the header using HttpInterceptor, It renders the user data by making the consensus between client and server.
- We have completed this task earlier, but we will execute when the login API is being requested.
- Use reactive to get and validate the form values.
- Redirect to profile page when successfully login.
- Display form error in the frontend.
Open signin.component.ts file and insert the following code.
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from './../../shared/auth.service';
import { FormBuilder, FormGroup } from "@angular/forms";
import { TokenService } from '../../shared/token.service';
import { AuthStateService } from '../../shared/auth-state.service';
@Component({
selector: 'app-signin',
templateUrl: './signin.component.html',
styleUrls: ['./signin.component.scss']
})
export class SigninComponent implements OnInit {
loginForm: FormGroup;
errors = null;
constructor(
public router: Router,
public fb: FormBuilder,
public authService: AuthService,
private token: TokenService,
private authState: AuthStateService,
) {
this.loginForm = this.fb.group({
email: [],
password: []
})
}
ngOnInit() { }
onSubmit() {
this.authService.signin(this.loginForm.value).subscribe(
result => {
this.responseHandler(result);
},
error => {
this.errors = error.error;
},() => {
this.authState.setAuthState(true);
this.loginForm.reset()
this.router.navigate(['profile']);
}
);
}
// Handle response
responseHandler(data){
this.token.handleData(data.access_token);
}
}
Open signin.component.html file and include the given below code.
<div class="auth-wrapper">
<form class="form-signin" [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<h3 class="h3 mb-3 font-weight-normal text-center">Sign in</h3>
<!-- Errors -->
<div *ngIf="errors?.email" class="alert alert-danger mt-3">
{{ errors?.email }}
</div>
<div *ngIf="errors?.password" class="alert alert-danger mt-3">
{{ errors?.password }}
</div>
<div *ngIf="errors?.error" class="alert alert-danger mt-3">
{{ errors?.error }}
</div>
<!-- Login -->
<div class="form-group">
<label>Email address</label>
<input type="email" class="form-control" formControlName="email">
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" formControlName="password">
</div>
<button type="submit" class="btn btn-block btn-primary">Log in</button>
</form>
</div>
Display User Profile
To display user profile subscribe to the profileUser()
method via AuthService, in response, we get the user data that we fetch by making the HTTP POST request through Laravel API. Display the data using the interpolation sign inside the user profile template.
Open user-profile.component.ts file and paste the following code.
import { Component, OnInit } from '@angular/core';
import { AuthService } from './../../shared/auth.service';
// User interface
export class User {
name: String;
email: String;
}
@Component({
selector: 'app-user-profile',
templateUrl: './user-profile.component.html',
styleUrls: ['./user-profile.component.scss']
})
export class UserProfileComponent implements OnInit {
UserProfile: User;
constructor(
public authService: AuthService
) {
this.authService.profileUser().subscribe((data:any) => {
this.UserProfile = data;
})
}
ngOnInit() { }
}
Open user-profile.component.html file and incorporate the following code within.
<div class="container">
<div class="card inner-main">
<div class="card-header">
User Profile
</div>
<div class="card-body">
<p class="card-text">Name: <strong>{{UserProfile?.name}}</strong></p>
<p class="card-text">Email: <strong>{{UserProfile?.email}}</strong></p>
</div>
</div>
</div>
Logout
We are going to use simple logic to make the user log out from the app. Remove the JWT token from local storage, set the authentication state to false.
Create a isSignedIn variable, It hide and show navigation items based on auth state. Access userAuthState observable through AuthStateService, subscribe and assign the response to the
variable.
Open app.component.ts file and insert the following code.
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { TokenService } from './shared/token.service';
import { AuthStateService } from './shared/auth-state.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
isSignedIn: boolean;
constructor(
private auth: AuthStateService,
public router: Router,
public token: TokenService,
) {
}
ngOnInit() {
this.auth.userAuthState.subscribe(val => {
this.isSignedIn = val;
});
}
// Signout
signOut() {
this.auth.setAuthState(false);
this.token.removeToken();
this.router.navigate(['login']);
}
}
Open app.component.html file and insert the following code.
<div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm fixed-top">
<h5 class="my-0 mr-md-auto font-weight-normal">Laravel Angular JWT Auth</h5>
<nav class="my-2 my-md-0 mr-md-3">
<a class="p-2 text-dark" routerLink="/profile" *ngIf="isSignedIn">User Profile</a>
<a class="p-2 text-dark" *ngIf="!isSignedIn" routerLink="/login">Log in</a>
<a class="p-2 text-dark" routerLink="/register">Register</a>
</nav>
<button class="btn btn-outline-primary" (click)="signOut()" *ngIf="isSignedIn">Log out</button>
</div>
<router-outlet></router-outlet>
Start The Laravel App
Start the local web server, get inside the laravel project folder and run the app.
cd backend && php artisan serve
Start The Angular App
Head over to angular project folder and run the app.
cd frontend && ng serve --open
Conclusion
We have completed the Laravel and Angular tutorials. In this tutorial, we learned how to authenticate with the JWT token. A user can register, signin, and view user profiles securely.
In the upcoming tutorial, we will also learn to build forget and reset passwords, log in with social media platforms, route protection with guards, and sending a verification email functionality.
Anyway, If you are new to Laravel and Angular development, after completing this tutorial, you will be able to comprehend almost the entire user authentication process.
You can get the complete code of this tutorial on GitHub.