Angular 9 Firebase Auth – Email/Password Authentication

Angular 9 Firebase Auth – Email/Password Authentication with AngularFire2 v4

In this tutorial, we’re gonna look at way to implement Email/Password authentication (with form validation) using AngularFire2 v4.

Related Posts:
How to integrate Firebase with Angular 9
Angular 9 Firebase Auth – Anonymous Authentication with AngularFire2 v4

I. Technology

– Angular 9
– AngularFire2 4.0

II. Overview

We will build an Angular 9 App that allows user sign up and login (with form validation):
angular-4-firebase-auth-email-password-overview

II. How to do

1. Set up the Firebase Project & Install AngularFire2

Please visit this post to know step by step.

angular-4-firebase-integration-copy-firebase-project-config

2. Enable Firebase Auth for Email/Password

Go to your Project on Firebase Console -> Authentication tab -> SIGN-IN METHOD -> enable Email/Password:
angular-4-firebase-auth-email-password-enable-console

3. Auth Service


import {AngularFireAuth} from 'angularfire2/auth';

@Injectable()
export class AuthService {

  authState: any = null;

  constructor(private afAuth: AngularFireAuth, private router: Router) {
    this.afAuth.authState.subscribe((auth) => {
      this.authState = auth
    });
  }

  get isUserAnonymousLoggedIn(): boolean {
    return (this.authState !== null) ? this.authState.isAnonymous : false
  }

  get currentUserId(): string {
    return (this.authState !== null) ? this.authState.uid : ''
  }

  get currentUserName(): string {
    return this.authState['email']
  }

  get currentUser(): any {
    return (this.authState !== null) ? this.authState : null;
  }

  get isUserEmailLoggedIn(): boolean {
    if ((this.authState !== null) && (!this.isUserAnonymousLoggedIn)) {
      return true
    } else {
      return false
    }
  }

  signUpWithEmail(email: string, password: string) {
    return this.afAuth.auth.createUserWithEmailAndPassword(email, password)
      .then((user) => {
        this.authState = user
      })
      .catch(error => {
        console.log(error)
        throw error
      });
  }

  loginWithEmail(email: string, password: string) {
    return this.afAuth.auth.signInWithEmailAndPassword(email, password)
      .then((user) => {
        this.authState = user
      })
      .catch(error => {
        console.log(error)
        throw error
      });
  }

  signOut(): void {
    this.afAuth.auth.signOut();
    this.router.navigate(['/'])
  }
}

– We subscribe to the AngularFire auth observable that returns a FirebaseAuthState object. This object is null when logging out, and contains useful User Information (UID, Display Name, Photo URL…) when logging in.
– We use:
+ AngularFireAuth.auth.createUserWithEmailAndPassword() to sign up new account.
+ AngularFireAuth.auth.signInWithEmailAndPassword() to log in.
+ AngularFireAuth.auth.signOut() to log out.
– We also catch Exception to get Error information and throw it for register/login validation (Error will be catch later at Component which uses this service’s functions)

4. App Module


// ...
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';

import {AngularFireModule} from 'angularfire2';
import {AngularFireAuthModule} from 'angularfire2/auth';

import {AuthService} from './auth/auth.service';

@NgModule({
  // ...
  imports: [
    BrowserModule,
    FormsModule,
    AngularFireModule.initializeApp(environment.firebase),
    AngularFireAuthModule
  ],
  providers: [AuthService],
  // ...
})

5. Use Service – Login Component


import {Component, OnInit} from '@angular/core';
import {Router} from '@angular/router';
import {AuthService} from '../auth.service';

@Component({
  selector: 'user-login',
  templateUrl: './user-login.component.html',
  styleUrls: ['./user-login.component.css']
})
export class UserLoginComponent implements OnInit {

  email = '';
  password = '';
  errorMessage = '';
  error: {name: string, message: string} = {name: '', message: ''};

  constructor(public authService: AuthService, private router: Router) {}

  ngOnInit() {
  }

  onSignUp(): void {
    if (this.validateForm(this.email, this.password)) {
      this.authService.signUpWithEmail(this.email, this.password)
        .then(() => {
          this.router.navigate(['/user'])
        }).catch(_error => {
          this.error = _error
          this.router.navigate(['/'])
        })
    }
  }

  onLoginEmail(): void {
    if (this.validateForm(this.email, this.password)) {
      this.authService.loginWithEmail(this.email, this.password)
        .then(() => this.router.navigate(['/user']))
        .catch(_error => {
          this.error = _error
          this.router.navigate(['/'])
        })
    }
  }

  validateForm(email: string, password: string): boolean {
    // validate this.errorMessage
  }
}

We will validate 2 times:
– before calling AuthService using validateForm()
– after AuthService throws an error using firebase.Thenable.catch()

Template:

<p *ngIf="errorMessage.length > 0" class="text-danger">
	{{errorMessage}}</p>

<p *ngIf="error.message.length > 0" class="text-danger">
	{{error.message}}</p>

<form (ngSubmit)="onSignUp()">
	<div class="form-group">
		<label for="email">Email</label> <input type="email"
			class="form-control" id="email" name="email" required
			[(ngModel)]="email">
	</div>

	<div class="form-group">
		<label for="password">Password</label> <input type="password"
			class="form-control" id="password" name="password" required
			[(ngModel)]="password">
	</div>

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

III. Practice

1. Project structure

angular-4-firebase-auth-anonymous-structure

angular-4-firebase-auth-email-password-overview-component

2. App Module

import {environment} from '../environments/environment';
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {AppRoutingModule} from './app-routing.module';

import {AngularFireModule} from 'angularfire2';
import {AngularFireAuthModule} from 'angularfire2/auth';

import {AuthService} from './auth/auth.service';

import {AppComponent} from './app.component';
import {UserLoginComponent} from './auth/user-login/user-login.component';
import {UserInfoComponent} from './auth/user-info/user-info.component';

@NgModule({
  declarations: [
    AppComponent,
    UserLoginComponent,
    UserInfoComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    AppRoutingModule,
    AngularFireModule.initializeApp(environment.firebase),
    AngularFireAuthModule
  ],
  providers: [AuthService],
  bootstrap: [AppComponent]
})
export class AppModule {}

3. Auth Service


import {Injectable} from '@angular/core';
import {Router} from '@angular/router';
import {AngularFireAuth} from 'angularfire2/auth';

@Injectable()
export class AuthService {

  authState: any = null;

  constructor(private afAuth: AngularFireAuth, private router: Router) {
    this.afAuth.authState.subscribe((auth) => {
      this.authState = auth
    });
  }

  get isUserAnonymousLoggedIn(): boolean {
    return (this.authState !== null) ? this.authState.isAnonymous : false
  }

  get currentUserId(): string {
    return (this.authState !== null) ? this.authState.uid : ''
  }

  get currentUserName(): string {
    return this.authState['email']
  }

  get currentUser(): any {
    return (this.authState !== null) ? this.authState : null;
  }

  get isUserEmailLoggedIn(): boolean {
    if ((this.authState !== null) && (!this.isUserAnonymousLoggedIn)) {
      return true
    } else {
      return false
    }
  }

  signUpWithEmail(email: string, password: string) {
    return this.afAuth.auth.createUserWithEmailAndPassword(email, password)
      .then((user) => {
        this.authState = user
      })
      .catch(error => {
        console.log(error)
        throw error
      });
  }

  loginWithEmail(email: string, password: string) {
    return this.afAuth.auth.signInWithEmailAndPassword(email, password)
      .then((user) => {
        this.authState = user
      })
      .catch(error => {
        console.log(error)
        throw error
      });
  }

  signOut(): void {
    this.afAuth.auth.signOut();
    this.router.navigate(['/'])
  }
}

4. Components

4.1 User Login Component

user-login.component.ts


import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../auth.service';

@Component({
  selector: 'user-login',
  templateUrl: './user-login.component.html',
  styleUrls: ['./user-login.component.css']
})
export class UserLoginComponent implements OnInit {

  isNewUser = true;
  email = '';
  password = '';
  errorMessage = '';
  error: { name: string, message: string } = { name: '', message: '' };

  resetPassword = false;

  constructor(public authService: AuthService, private router: Router) { }

  ngOnInit() { }

  checkUserInfo() {
    if (this.authService.isUserEmailLoggedIn) {
      this.router.navigate(['/user'])
    }
  }

  clearErrorMessage() {
    this.errorMessage = '';
    this.error = { name: '', message: '' };
  }

  changeForm() {
    this.isNewUser = !this.isNewUser
  }

  onSignUp(): void {
    this.clearErrorMessage()

    if (this.validateForm(this.email, this.password)) {
      this.authService.signUpWithEmail(this.email, this.password)
        .then(() => {
          this.router.navigate(['/user'])
        }).catch(_error => {
          this.error = _error
          this.router.navigate(['/'])
        })
    }
  }

  onLoginEmail(): void {
    this.clearErrorMessage()

    if (this.validateForm(this.email, this.password)) {
      this.authService.loginWithEmail(this.email, this.password)
        .then(() => this.router.navigate(['/user']))
        .catch(_error => {
          this.error = _error
          this.router.navigate(['/'])
        })
    }
  }

  validateForm(email: string, password: string): boolean {
    if (email.length === 0) {
      this.errorMessage = 'Please enter Email!'
      return false
    }

    if (password.length === 0) {
      this.errorMessage = 'Please enter Password!'
      return false
    }

    if (password.length < 6) {
      this.errorMessage = 'Password should be at least 6 characters!'
      return false
    }

    this.errorMessage = ''

    return true
  }

  isValidMailFormat(email: string) {
    const EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;

    if ((email.length === 0) && (!EMAIL_REGEXP.test(email))) {
      return false;
    }

    return true;
  }

  sendResetEmail() {
    this.clearErrorMessage()

    this.authService.resetPassword(this.email)
      .then(() => this.resetPassword = true)
      .catch(_error => {
        this.error = _error
      })
  }
}

user-login.component.html

{{checkUserInfo()}}
<div *ngIf="!authService.isUserEmailLoggedIn">
	<div style="width: 350px;" *ngIf="isNewUser">

		<p *ngIf="errorMessage.length > 0" class="text-danger">
			{{errorMessage}}</p>

		<p *ngIf="error.message.length > 0" class="text-danger">
			{{error.message}}</p>

		<form (ngSubmit)="onSignUp()">
			<div class="form-group">
				<label for="email">Email</label>
				<input type="email" class="form-control" id="email" name="email" required [(ngModel)]="email">
			</div>

			<div class="form-group">
				<label for="password">Password</label>
				<input type="password" class="form-control" id="password" name="password" required [(ngModel)]="password">
			</div>

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

		<h4 class="text-primary" (click)="changeForm()">Already have an Account? >> Log In</h4>
	</div>

	<div style="width: 350px;" *ngIf="!isNewUser">

		<p *ngIf="errorMessage.length > 0" class="text-danger">
			{{errorMessage}}</p>

		<p *ngIf="error.message.length > 0" class="text-danger">
			{{error.message}}</p>

		<form (ngSubmit)="onLoginEmail()">
			<div class="form-group">
				<label for="email">Email</label>
				<input type="text" class="form-control" id="email" name="email" required [(ngModel)]="email">
			</div>

			<div class="form-group">
				<label for="password">Password</label>
				<input type="password" class="form-control" id="password" name="password" required [(ngModel)]="password">
			</div>

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

		<h4 class="text-primary" (click)="changeForm()">Not have any Account yet? >> Register</h4>

		<a *ngIf="!resetPassword && isValidMailFormat(email)" class="text-danger" (click)="sendResetEmail()">Reset Password for {{email}}</a>
		<p *ngIf="resetPassword" class="text-success">Check your email to reset password!</p>

	</div>
</div>

4.2 User Info Component

user-info.component.ts


import {Component, OnInit} from '@angular/core';
import {AuthService} from '../auth.service';

@Component({
  selector: 'user-info',
  templateUrl: './user-info.component.html',
  styleUrls: ['./user-info.component.css']
})
export class UserInfoComponent implements OnInit {

  constructor(public authService: AuthService) {}

  ngOnInit() {
  }

  logout() {
    this.authService.signOut();
  }

}

user-info.component.html

<div *ngIf="authService.currentUser">
	<h5 class="text-primary">User Information</h5>
	<h4>
		<strong>UID:</strong> {{ authService.currentUserId }}
	</h4>
	<h4>
		<strong>Email:</strong> {{ authService.currentUserName }}
	</h4>
	<button class="button" (click)="logout()">Logout</button>
</div>

5. App Routing Module

app-routing.module.ts


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

import {UserLoginComponent} from './auth/user-login/user-login.component';
import {UserInfoComponent} from './auth/user-info/user-info.component';

const routes: Routes = [
  {path: '', redirectTo: 'login', pathMatch: 'full'},
  {path: 'login', component: UserLoginComponent},
  {path: 'user', component: UserInfoComponent},
];

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

export class AppRoutingModule {}

6. App Component

app.component.ts


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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'JavaSampleApproach';
  description = 'Angular4-Firebase Demo';
}

app.component.html

<div class="container">
	<div style="color: blue; margin-bottom:20px">
		<h1>{{title}}</h1>
		<h3>{{description}}</h3>
	</div>

	<router-outlet></router-outlet>
</div>

7. Check Result

Run the App, go to http://localhost:4200/.

Register and Login:
angular-4-firebase-auth-email-password-login-result

Firebase Console:
angular-4-firebase-auth-email-password-console-result

Check Validation:
angular-4-firebase-auth-email-password-validation-result

IV. Source Code

Angular4Firebase-Auth-Email-Password



By grokonez | March 25, 2021.


Related Posts


Got Something To Say:

Your email address will not be published. Required fields are marked *

*