Auth: Login & Signup in Angular 18
In this step by step tutorial, we will see by example how to build login and signup pages using Angular 18. We'll leverage HTML and CSS to design the pages, and Angular code to implement the functionality. By taking a reactive approach, we'll manage form data and submit it to the authentication endpoint using Angular's HttpClient module.
Setting Up the Authentication Backend
Welcome to our tutorial on building login and signup pages with Angular 18! In this guide, we'll walk you through the process of building authentication functionality within an Angular 18 application.
To kickstart our project, we'll use a robust authentication backend provided by a Node.js application available at https://github.com/techiediaries/node-mongoose-jwt
. This backend app is powered by MongoDB and implements JSON Web Tokens (JWT) for secure user authentication. Before proceeding, make sure you have MongoDB installed on your system.
To get started, clone the repository for the authentication backend, navigate into its directory, and follow the instructions below to set it up:
npm install
Next create an .env
file and add the following contents:
CONNECTION_STRING= mongodb://127.0.0.1:27017/myapp
JWT_SECRET= secret123456789
Next, run the backend using this command:
npm start
You app JWT authentication backend will be listening at http://localhost:3000
.
Setting Up Angular 18 Authentication Frontend
Are you ready to embark on the journey of building a robust frontend for your Angular 18 application? Let's dive in and harness the power of Angular to create dynamic login, signup, and admin pages.
To begin, open a new terminal window and initiate a new Angular 18 project using the Angular CLI's ng new command. This command sets up a new Angular 18 workspace with all the necessary files and dependencies to kickstart your development process. Navigate inside your project and create three components for login, signup and admin:
ng g c pages/login
ng g c pages/signup
ng g c pages/admin
In our quest to develop a robust authentication system for our Angular 18 application, there's a crucial step awaiting us: the creation of an authentication service and guard. These essential components play a pivotal role in managing user authentication and securing our application's routes. Run these commands:
ng g s auth/auth
ng g guard auth/auth
Choose CanActivate
for the authentication guard:
❯◉ CanActivate
◯ CanActivateChild
◯ CanDeactivate
◯ CanMatch
Then press Enter.
Routing Configuration
As we continue our journey of building a robust authentication system with Angular 18, it's time to configure our application routes. Routing plays a crucial role in guiding users through different pages and ensuring seamless navigation within our application. Additionally, we'll implement route protection to restrict access to certain components, such as the admin panel, to authenticated users only. Open the src/app/app.routes.ts
file and update it as follows:
import { Routes } from '@angular/router';
import { LoginComponent } from './pages/login/login.component';
import { SignupComponent } from './pages/signup/signup.component';
import { AdminComponent } from './pages/admin/admin.component';
import { authGuard } from './auth/auth.guard';
export const routes: Routes = [
{
path: '', redirectTo: '/login', pathMatch: 'full'
},
{
path: 'login', component: LoginComponent
},
{
path: 'signup', component: SignupComponent
},
{
path: 'admin', component: AdminComponent, canActivate: [authGuard]
}
];
As you can see we are using the redirectTo
attribute to redirect users to the login page when they visit the home path and the canActivate
attribute to protect the admin page from non authenticated users. We'll implement the authentication guard later.
Implementing the Authentication Service
As we continue to build our Angular 18 application with a focus on authentication, it's essential to establish communication with our backend authentication server seamlessly. To facilitate this interaction, we'll leverage Angular's HttpClient service, a powerful tool for making HTTP requests and handling responses.
Before diving into communication with the authentication backend, we must ensure that our Angular application is equipped with the necessary dependencies and configurations to use the HttpClient service effectively. This involves providing the HttpClient module within our application setup.
To accomplish this, we'll navigate to the src/app/app.config.ts
file and configure the required imports and dependencies. By incorporating the HttpClient module into our application configuration, we lay the groundwork for seamless communication with the authentication backend.
Open the src/app/app.config.ts
file and add the following import:
import { provideHttpClient } from '@angular/common/http';
Next, call provideHttpClient()
inside the providers
array:
export const appConfig: ApplicationConfig = {
providers: [provideRouter(routes), provideHttpClient()]
};
Next, let's implement the authentication service. Open the src/app/auth/auth.service.ts
file and start by adding the following imports:
import { HttpClient } from '@angular/common/http';
import { inject } from '@angular/core';
import { tap } from 'rxjs/operators';
In the authentication service, inject the HttpClient
service using the inject
method and define a base URL that contains the URL of our auth backend:
httpClient = inject(HttpClient);
baseUrl = 'http://localhost:3000/api';
Next, define the signup()
method of the authentication service:
signup(data: any) {
return this.httpClient.post(`${this.baseUrl}/register`, data);
}
Define the login()
method of the authentication service:
login(data: any) {
return this.httpClient.post(`${this.baseUrl}/login`, data)
.pipe(tap((result) => {
localStorage.setItem('authUser', JSON.stringify(result));
}));
}
Next, define the logout()
method:
logout() {
localStorage.removeItem('authUser');
}
Finally define the isLoggedIn()
method:
isLoggedIn() {
return localStorage.getItem('authUser') !== null;
}
Implementing the Authentication Guard
Continuing our journey towards building a secure authentication system in Angular 18, our next step is to implement the authentication guard. The authentication guard serves as a crucial line of defense, ensuring that only authenticated users can access protected routes within our application. Open the src/app/auth/auth.guard.ts
file and add these imports:
import { inject } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from './auth.service';
Next, inside the authGuard
function inject the authentication and router services:
const authService = inject(AuthService);
const router = inject(Router);
Next, add the following code:
if (authService.isLoggedIn()) {
return true;
}
router.navigate(['/login']);
return false;
This simply instructs Angular 18 to automatically redirect users to the login page if they attempt to access protected routes without being logged in.
Adding the Login Component
Embarking on the implementation of our Login Component marks a significant stride in crafting a comprehensive authentication system within our Angular 18 application. The Login Component serves as the gateway for users to access secured areas of our application, requiring authentication credentials for entry. Open the src/app/pages/login/login.component.ts
file and add the following imports:
import { inject } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { Router, RouterModule } from '@angular/router';
import { AuthService } from '../../auth/auth.service';
Next, add the reactive forms and router modules inside the imports
array of the login component:
@Component({
selector: 'app-login',
standalone: true,
imports: [ ReactiveFormsModule, RouterModule],
templateUrl: './login.component.html',
styleUrl: './login.component.css'
})
Next, inject the authentication and router services using the inject
method:
authService = inject(AuthService);
router = inject(Router);
Adding the login form
Next, add a form group to the login component:
protected loginForm = new FormGroup({
email: new FormControl('', [Validators.required, Validators.email]),
password: new FormControl('', [Validators.required])
})
The login form contains an email and password controls with validation.
Next, add the onSubmit()
method to the login component:
onSubmit(){
if(this.loginForm.valid){
console.log(this.loginForm.value);
this.authService.login(this.loginForm.value)
.subscribe((data: any) => {
if(this.authService.isLoggedIn()){
this.router.navigate(['/admin']);
}
console.log(data);
});
}
}
This method checks if the form is valid, then attempts to log in with the AuthService
and navigates to an admin page upon successful authentication.
Adding the HTML form for login
Open the src/app/pages/login/login.component.html
file and add the following HTML form:
<div class="login-card">
<div class="card-title">
<h1>Login</h1>
<span>You don't have an account? <a routerLink="/signup">Sign up</a></span>
</div>
<form class="form-group" [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<input name="email" type="email" formControlName="email" placeholder="Email">
<input type="password" formControlName="password" placeholder="Password">
<button>Submit</button>
</form>
</div>
This code is an Angular template for a login form. It uses a combination of HTML, Angular directives, and reactive forms to create a login card with a title, a link to sign up, and a form that submits login information.
Next, open the src/app/pages/login/login.component.css
file and style the login form as follows:
* {
box-sizing: border-box;
}
:host {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(253, 101, 133, 1);
}
.login-card {
display: flex;
flex-direction: column;
margin: 10px 10px;
box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.3);
background-color: #ffffff;
padding: 10px;
border-radius: 10px;
width: 40%;
}
.login-card input {
margin: 5px 0;
width: 100%;
background-color: #e2e2e2;
border: none;
outline: none;
padding: 12px 20px;
border-radius: 4px;
}
.login-card button {
background-color: #4796ff;
color: #ffffff;
font-size: 16px;
outline: none;
border-radius: 5px;
border: none;
padding: 8px 15px;
width: 100%;
}
.card-title h1 {
font-size: 26px;
font-weight: bold;
}
Adding the Signup Component
With the groundwork laid for our authentication system with Angular 18, it's time to turn our attention to the implementation of the Signup Component. This pivotal component empowers users to create new accounts within our application, enabling them to access its features and functionalities securely. Open the src/app/pages/signup/signup.component.ts
file and add the following imports:
import { inject } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { Router, RouterModule } from '@angular/router';
import { AuthService } from '../../auth/auth.service';
Next, add the reactive forms and router modules to the imports
array of the signup component:
@Component({
selector: 'app-signup',
standalone: true,
imports: [ReactiveFormsModule, RouterModule],
templateUrl: './signup.component.html',
styleUrl: './signup.component.css'
})
Next, inject the authentication and router services:
authService = inject(AuthService);
router = inject(Router);
Next, create the reactive form for signing up users:
public signupForm = new FormGroup({
name: new FormControl('', [Validators.required]),
email: new FormControl('', [Validators.required, Validators.email]),
password: new FormControl('', [Validators.required])
})
Finally, define the onSubmit()
method as follows:
public onSubmit() {
if (this.signupForm.valid) {
console.log(this.signupForm.value);
this.authService.signup(this.signupForm.value)
.subscribe({
next: (data: any) => {
console.log(data);
this.router.navigate(['/login']);
},
error: (err) => console.log(err)
});
}
}
Now open the src/app/pages/signup/signup.component.html
file and the HTML form for signup:
<div class="signup-card">
<div class="card-title">
<h1>Create Account</h1>
<span>Already have an account? <a routerLink="/login">Sign In</a></span>
</div>
<form class="form-group" [formGroup]="signupForm" (ngSubmit)="onSubmit()">
<input type="text" name="name" placeholder="Name" formControlName="name">
<input type="email" name="email" placeholder="Email" formControlName="email">
<input type="password" name="password" placeholder="Password" formControlName="password">
<input type="submit" value="Signup">
</form>
<div class="card-terms">
<input type="checkbox"> <span>I have read and agree to the <a href="">Terms of Service</a></span>
</div>
</div>
Open the src/app/pages/signup/signup.component.css
and style the signup page:
* {
box-sizing: border-box;
}
:host {
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: rgba(253, 101, 133, 1);
}
.signup-card {
border-radius: 10px;
box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.3);
width: 40%;
height: 450px;
background-color: #ffffff;
padding: 10px 30px;
}
.card-title {
padding: 10px;
}
.card-title h1 {
font-size: 26px;
font-weight: bold;
}
.form-group input {
margin: 5px 0;
width: 100%;
background-color: #e2e2e2;
border: none;
outline: none;
padding: 12px 20px;
border-radius: 4px;
}
.form-group input[type="submit"] {
background-color: #4796ff;
color: #ffffff;
font-size: 16px;
outline: none;
border-radius: 5px;
border: none;
padding: 8px 15px;
width: 100%;
}
.card-terms {
display: flex;
align-items: center;
padding: 10px;
}
.card-terms span {
margin: 5px;
font-size: 13px;
}
Implementing the Admin Page
As our authentication system takes shape, it's time to introduce the Admin Page—a central hub where authorized users can manage privileged functionalities and access exclusive features within our Angular 18 application.
Open the src/app/pages/admin/admin.component.ts
file and update it as follows:
import { Component, inject } from '@angular/core';
import { AuthService } from '../../auth/auth.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-admin',
standalone: true,
imports: [],
templateUrl: './admin.component.html',
styleUrl: './admin.component.css'
})
export class AdminComponent {
authService = inject(AuthService);
router = inject(Router);
public logout(){
this.authService.logout();
this.router.navigate(['/login']);
}
}
Open the src/app/pages/admin/admin.component.html
file and update it as follows:
<button (click)="logout()">Logout</button>
Open the src/app/pages/admin/admin.component.css
file and update it as follows:
:host {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
background-color: rgba(253, 101, 133, 1);
}
button {
padding: 20px;
background-color: rgba(60, 10, 107, 0.562);
border-radius: 10px;
border: 0;
outline: none;
width: 300px;
}
Finally open the src/app/app.component.html
file and clear everything then add the router outlet:
<router-outlet></router-outlet>
Then open the src/styles.css
file and the following styles:
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap");
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
Serve your app using the ng serve
command.
Conclusion
In summary, we've embarked on the development journey of building a comprehensive authentication system within our Angular 18 application. Our focus has shifted through the implementation of key components, including the Login Component, Signup Component, and Admin Page. Each component leverages Angular's capabilities to create intuitive user interfaces, facilitate secure authentication processes, and provide elevated privileges for authorized users.
-
Date: