In this post, we will add Google’s Firebase service in an Ionic Application to use Firebase Authentication service. We’ll create login, registration and dashboard pages using which a user can register with email and password after login user will be redirected to the Dashboard.
Firebase is a powerful cloud-based service provider for development as well production level. It is well known for cloud services like Authentication, Analytics, Messaging services, Firestore (No SQL Database), Storage ( store multimedia files ), Social Login and many more.
We’ll use the Authentication service and create an application to demonstrate Login and Registration functionality where a user can log in as well as Register if not having an account already using Email ID and Password. We will also validate user inputs using Angular’s Reactive Form Validation. After successful login user can click on Logout link to go back to the login screen from the dashboard.
Let’s get started!
Update to the latest version
Make sure you have the latest version of @ionic/cli
package installed. You can update it by running below command in the terminal window.
$ npm install -g @ionic/cli
The current version of @ionic/cli
is version 6.6.0
Create new Ionic App
Now create a new Ionic application using Angular framework using --type=angular
option with starter blank
template. Run the following command in the terminal to create a new application.
$ ionic start ionic-firebase-email-authentication blank --type=angular
move to the application folder
$ cd ionic-firebase-email-authentication
then open application folder in Visual Studio Code in installed by running
$ code .
Install Firebase in Ionic Application
The angularfire
is a Firebase official package for Angular applications. This package lets an Angular project to use all Firebase services.
For using the Firebase services we'll install the @angular/fire
and firebase
packages by running following npm command.
$ npm install firebase @angular/fire --save
Integrate Firebase Project in Ionic Application
Next, we need to create a Firebase app in the Firebase Console then get credential which will be added in our Ionic Application to connect to Firebase application.
Follow these steps to create a new Firebase project and application:
Step 1) Visit Firebase here then click on Get Started if you have not created an account yet.
Step 2) Click on "Add project" then enter app-related information click on "create"
Step 3) Next click on "Web App" icon to get configuration text with app secret info which we will add in out Ionic 4 Application to communicate with services related to this Firebase project.
Step 4) As we are going to add Email registration, let's enable Email authentication by clicking on "Authentication" link on left sidebar then click on "Sign-in method" tab. After that enable "Email/Password" option.
Update environment file to add Firebase configuration
After creating a Firebase application you need to update the "~ionic-firebase-email-authentication/src/environments/environment.ts" file with the credential you got In previous steps as shown below.
export const environment = {
production: false,
firebase: {
apiKey: "AIzXXXXXXXXXXXXXXXWZMPN90HFrp4",
authDomain: "test-projeXXXXXXX.firebaseapp.com",
databaseURL: "https://test-projeXXXXXXX.firebaseio.com",
projectId: "test-projeXXXXXXX7",
storageBucket: "test-projeXXXXXXXX.appspot.com",
messagingSenderId: "446XXXXXX105"
}
};
Note: Replace the above values with your Firebase project credentials
Note 2: You can now delete the home page as we will create new pages as per example application like Login, Register, Dashboard and also create a service to communicate with Firebase Database called Firestore.
Create Pages using following Ionic CLI shortcuts
Run the following generate commands to create new pages required for our login authentication application.
$ ionic generate page login
$ ionic generate page register
$ ionic generate page dashboard
To communicate with the Firebase Authentication methods and keep login, register and logout logic separate, create a new service by running below generate command
$ ionic g service services/authentication
Update the Service with Login, Register and Logout Methods
We have created a new service at "~ionic-firebase-email-authentication/src/app/services/authentication.service.ts". The AuthenticateService will have methods for login, register, get user details and logout.
To register new user in Firebase Authentication service, we'll call the createUserWithEmailAndPassword()
method with email and password provided by a user from register page.
For Log in a user, the signInWithEmailAndPassword()
is called available in the AngularFireAuth
class.
The signOut()
method available in the AngularFireAuth
class will remove the user session in the Firebase Authentication service.
Also, we have a userDetails()
method which will return details od logged in user.
As this service is set to providedIn
to root
so we don't need to add this service in the providers
array in any module.
// authentication.service.ts
import { Injectable } from "@angular/core";
import { AngularFireAuth } from '@angular/fire/auth';
@Injectable({
providedIn: 'root'
})
export class AuthenticateService {
constructor(
private afAuth: AngularFireAuth
) { }
registerUser(value) {
return new Promise<any>((resolve, reject) => {
this.afAuth.createUserWithEmailAndPassword(value.email, value.password)
.then(
res => resolve(res),
err => reject(err))
})
}
loginUser(value) {
return new Promise<any>((resolve, reject) => {
this.afAuth.signInWithEmailAndPassword(value.email, value.password)
.then(
res => resolve(res),
err => reject(err))
})
}
logoutUser() {
return new Promise((resolve, reject) => {
if (this.afAuth.currentUser) {
this.afAuth.signOut()
.then(() => {
console.log("LOG Out");
resolve();
}).catch((error) => {
reject();
});
}
})
}
userDetails() {
return this.afAuth.user
}
}
After deleting the home page and creating above new pages and service (authentication.service.ts) our app's directory structure will look like this.
Changes in App'module and routing module
We need to make changes in the app.module.ts and app-routing.module.ts file to include Firebase module's and update routing default paths as we have deleted the Home page.
app.module.ts
Here we'll import the AngularFireModule
and AngularFireAuthModule
modules. If you need to use other Firebase services just import them here as well. We'll also initialize the AngularFireModule
with firebase credentials using configuration we have in the environment
file.
// app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouteReuseStrategy } from '@angular/router'; import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; import { SplashScreen } from '@ionic-native/splash-screen/ngx'; import { StatusBar } from '@ionic-native/status-bar/ngx'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; import { AngularFireModule } from '@angular/fire'; import { AngularFireAuthModule } from '@angular/fire/auth'; import { environment } from '../environments/environment'; @NgModule({ declarations: [AppComponent], entryComponents: [], imports: [ BrowserModule, IonicModule.forRoot(), AppRoutingModule, AngularFireAuthModule, AngularFireModule.initializeApp(environment.firebase) ], providers: [ StatusBar, SplashScreen, { provide: RouteReuseStrategy, useClass: IonicRouteStrategy } ], bootstrap: [AppComponent] }) export class AppModule { }
app-routing.module.ts
// app-routing.module.ts import { NgModule } from '@angular/core'; import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; const routes: Routes = [ // { // path: 'home', // loadChildren: () => import('./home/home.module').then( m => m.HomePageModule) // }, { path: '', redirectTo: 'login', pathMatch: 'full' }, { path: 'login', loadChildren: () => import('./login/login.module').then(m => m.LoginPageModule) }, { path: 'register', loadChildren: () => import('./register/register.module').then(m => m.RegisterPageModule) }, { path: 'dashboard', loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardPageModule) }, ]; @NgModule({ imports: [ RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }) ], exports: [RouterModule] }) export class AppRoutingModule { }
Import FormsModule
and ReactiveFormsModule
As we are using Form Validations using React approach, in the login.module.ts and register.module.ts file we need to import the ReactiveFormsModule
in the imports
array
@NgModule({ imports: [ CommonModule, FormsModule, ReactiveFormsModule, IonicModule, ... ], declarations: [LoginPage] })
Login Page
Replace the following HTML and Component code having validation to check user input email and password. We have used Reactive form validation with defined rules in the component itself.
login.page.ts
// login.page.ts
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
import { NavController } from '@ionic/angular';
import { AuthenticateService } from '../services/authentication.service';
@Component({
selector: 'app-login',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {
validations_form: FormGroup;
errorMessage: string = '';
constructor(
private navCtrl: NavController,
private authService: AuthenticateService,
private formBuilder: FormBuilder
) { }
ngOnInit() {
this.validations_form = this.formBuilder.group({
email: new FormControl('', Validators.compose([
Validators.required,
Validators.pattern('^[a-zA-Z0-9_.+-][email protected][a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$')
])),
password: new FormControl('', Validators.compose([
Validators.minLength(5),
Validators.required
])),
});
}
validation_messages = {
'email': [
{ type: 'required', message: 'Email is required.' },
{ type: 'pattern', message: 'Please enter a valid email.' }
],
'password': [
{ type: 'required', message: 'Password is required.' },
{ type: 'minlength', message: 'Password must be at least 5 characters long.' }
]
};
loginUser(value) {
this.authService.loginUser(value)
.then(res => {
console.log(res);
this.errorMessage = "";
this.navCtrl.navigateForward('/dashboard');
}, err => {
this.errorMessage = err.message;
})
}
goToRegisterPage() {
this.navCtrl.navigateForward('/register');
}
}
login.page.html
<ion-header>
<ion-toolbar color="primary">
<ion-title>Login</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<form class="form" [formGroup]="validations_form" (ngSubmit)="loginUser(validations_form.value)">
<ion-item>
<ion-label position="floating" color="primary">Email</ion-label>
<ion-input type="text" formControlName="email"></ion-input>
</ion-item>
<div class="validation-errors">
<ng-container *ngFor="let validation of validation_messages.email">
<div class="error-message"
*ngIf="validations_form.get('email').hasError(validation.type) && (validations_form.get('email').dirty || validations_form.get('email').touched)">
{{ validation.message }}
</div>
</ng-container>
</div>
<ion-item>
<ion-label position="floating" color="primary">Password</ion-label>
<ion-input type="password" formControlName="password" class="form-controll" required></ion-input>
</ion-item>
<div class="validation-errors">
<ng-container *ngFor="let validation of validation_messages.password">
<div class="error-message"
*ngIf="validations_form.get('password').hasError(validation.type) && (validations_form.get('password').dirty || validations_form.get('password').touched)">
{{ validation.message }}
</div>
</ng-container>
</div>
<ion-button class="submit-btn" type="submit" [disabled]="!validations_form.valid">Log In</ion-button>
<label class="error-message">{{errorMessage}}</label>
</form>
<p class="go-to-register">
No account yet? <a (click)="goToRegisterPage()">Create an account.</a>
</p>
</ion-content>
Register Page
If the user is not registered then he will get an error message then registration is required. Replace following code in register.page.ts and register.page.html
register.page.ts
// register.page.ts
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
import { AuthenticateService } from '../services/authentication.service';
import { NavController } from '@ionic/angular';
@Component({
selector: 'app-register',
templateUrl: './register.page.html',
styleUrls: ['./register.page.scss'],
})
export class RegisterPage implements OnInit {
validations_form: FormGroup;
errorMessage: string = '';
successMessage: string = '';
validation_messages = {
'email': [
{ type: 'required', message: 'Email is required.' },
{ type: 'pattern', message: 'Enter a valid email.' }
],
'password': [
{ type: 'required', message: 'Password is required.' },
{ type: 'minlength', message: 'Password must be at least 5 characters long.' }
]
};
constructor(
private navCtrl: NavController,
private authService: AuthenticateService,
private formBuilder: FormBuilder
) { }
ngOnInit() {
this.validations_form = this.formBuilder.group({
email: new FormControl('', Validators.compose([
Validators.required,
Validators.pattern('^[a-zA-Z0-9_.+-][email protected][a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$')
])),
password: new FormControl('', Validators.compose([
Validators.minLength(5),
Validators.required
])),
});
}
tryRegister(value) {
this.authService.registerUser(value)
.then(res => {
console.log(res);
this.errorMessage = "";
this.successMessage = "Your account has been created. Please log in.";
}, err => {
console.log(err);
this.errorMessage = err.message;
this.successMessage = "";
})
}
goLoginPage() {
this.navCtrl.navigateBack('');
}
}
register.page.html
<ion-header>
<ion-toolbar color="primary">
<ion-title>Register</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<form class="form" [formGroup]="validations_form" (ngSubmit)="tryRegister(validations_form.value)">
<ion-item>
<ion-label position="floating" color="primary">Email</ion-label>
<ion-input type="text" formControlName="email"></ion-input>
</ion-item>
<div class="validation-errors">
<ng-container *ngFor="let validation of validation_messages.email">
<div class="error-message"
*ngIf="validations_form.get('email').hasError(validation.type) && (validations_form.get('email').dirty || validations_form.get('email').touched)">
{{ validation.message }}
</div>
</ng-container>
</div>
<ion-item>
<ion-label position="floating" color="primary">Password</ion-label>
<ion-input type="password" formControlName="password" class="form-controll" required></ion-input>
</ion-item>
<div class="validation-errors">
<ng-container *ngFor="let validation of validation_messages.password">
<div class="error-message"
*ngIf="validations_form.get('password').hasError(validation.type) && (validations_form.get('password').dirty || validations_form.get('password').touched)">
{{ validation.message }}
</div>
</ng-container>
</div>
<ion-button class="submit-btn" type="submit" [disabled]="!validations_form.valid">Register</ion-button>
<label class="error-message">{{errorMessage}}</label>
<label class="success-message">{{successMessage}}</label>
</form>
<p class="go-to-login">Already have an account? <a (click)="goLoginPage()">Try to Log In.</a></p>
</ion-content>
Dashboard Page
After the user successfully login with registered details will land on the dashboard page, which will also have a logout link on the footer.
dashboard.page.ts
// dashboard.page.ts
import { Component, OnInit } from '@angular/core';
import { NavController } from '@ionic/angular';
import { AuthenticateService } from '../services/authentication.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.page.html',
styleUrls: ['./dashboard.page.scss'],
})
export class DashboardPage implements OnInit {
userEmail: string;
constructor(
private navCtrl: NavController,
private authService: AuthenticateService
) { }
ngOnInit() {
this.authService.userDetails().subscribe(res => {
console.log('res', res);
if (res !== null) {
this.userEmail = res.email;
} else {
this.navCtrl.navigateBack('');
}
}, err => {
console.log('err', err);
})
}
logout() {
this.authService.logoutUser()
.then(res => {
console.log(res);
this.navCtrl.navigateBack('');
})
.catch(error => {
console.log(error);
})
}
}
dashboard.page.html
<ion-header>
<ion-toolbar>
<ion-title>Dashboard</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-grid>
<ion-row>
<ion-col text-center>
Welcome to Dashboard!
</ion-col>
</ion-row>
<ion-row>
<ion-col text-center>
Your Registered EmailID : {{userEmail}}
</ion-col>
</ion-row>
</ion-grid>
</ion-content>
<ion-footer (click)="logout()">
<ion-toolbar color="secondary">
<ion-title>Log out</ion-title>
</ion-toolbar>
</ion-footer>
That's it now we have a working Ionic Angular application using Firebase Authentication services, where a user can register and log in using email and password.
Now you can run the application by hitting the $ ionic serve --open
command in the terminal. The Ionic app will look like this
Get source code in GitHub Repo here
So in this post, we discussed how to integrate Google Firebase service in Ionic Application to create login and registration functionality. As per requirements, we can include more Firebase services like Firestore, Messaging, Social login which we will discuss in coming articles.
Pingback: Https auth ionic login Portal Guide Instructions Help - centtip.com
Pingback: Ionic 5|4 CRUD Operations Using Firebase with Firestore NoSQL Database Tutorial in Ionic Angular Application « Freaky Jolly
Thank you for a very helpful tutorial.
I also had to update authentication.service.ts by changing all lines with afAuth from afAuth to afAuth.auth.
Thx. It was very helpful.
Another great tutorial. One small tweak: change the generate service command from:
$ ionic g service services/authentication
to
$ ionic g service services/authenticate
So it matches up with the AuthenticateService name you use for the rest of the tutorial.
(There is also one mention of the original file path right after the generate command)
I would make a small change to allow for trailing whitespace in the email which is often inserted automatically by the phone keyboard.
Change the email REGEX in the login and register page to:
Validators.pattern(‘^[a-zA-Z0-9_.+-][email protected][a-zA-Z0-9-]+.[a-zA-Z0-9-.]+\\s*$’)
Then change the “value.email” on the authentication service to “value.email.trim()”