Angular 11 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 11
– Angular 11 Firebase Auth – Anonymous Authentication with AngularFire2 v4
I. Technology
– Angular 11
– AngularFire2 4.0
II. Overview
We will build an Angular 11 App that allows user sign up and login (with form validation):
II. How to do
1. Set up the Firebase Project & Install AngularFire2
Please visit this post to know step by step.
2. Enable Firebase Auth for Email/Password
Go to your Project on Firebase Console -> Authentication tab -> SIGN-IN METHOD -> enable Email/Password:
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
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:
Firebase Console:
Check Validation:
IV. Source Code
Angular4Firebase-Auth-Email-Password