Google Login Firebase for Angular Web app and Ionic Mobile App
Google oauth login can be implemented basically in the below ways.
- signInWithRedirect
-
signInWithPopup
- signInWithCredential
signInWithRedirect: works in web, but in mobile it gets redirected to browser, but never come back to your mobile app components.
signInWithPopup: works only for web, in mobile it gives the error like “not allowed”.
signInWithCredential: works for both web and mobile and it is the only recommended way for mobile as of today for ionic app implementations.
Why one more blog about ionic 4 google login implementation ?
- When I wanted to implement google login for one of my client, I got confused mainly in the “client id” term. Because we have web client id (client id generated for web application) and client id (generated for android app) in the google developer console.
- When you want to configure client id for ionic, you will get confused between these client ids, also the reverse client id.
params = { 'webClientId': 'MY_WEB_CLIENT_ID_GENERATED_BY_GOOGLE_OR_YOU_CAN_CREATE_YOUR_WEB_APP_AND_PUT_THAT_ID_HERE', 'offline': true }
And in the config.xml file:
<plugin name="cordova-plugin-googleplus" spec="7.0.1"> <variable name="REVERSED_CLIENT_ID" value="REVERSED_CLIENT_ID_OF_ANDROID_PLATFORM_CREATED_IN_GOOGLE_DEVELOPER_CONSOLE" /> <variable name="WEB_APPLICATION_CLIENT_ID" value="WEB_CLIENT_ID_AUTO_GENERATED_BY_GOOGLE_SAME_ONLY_WE_KEPT_IN_TYPESCRIPT_FILE_ABOVE_ALSO" /> <variable name="PLAY_SERVICES_VERSION" value="11.8.0" /> </plugin>
signInWithPopup Code Snippet:
Login.component.html:
<ion-content no-padding> <div class="main"> <ion-card no-margin class="card"> <ion-card-content> <ion-row> <ion-col> <ion-button expand="block" (click)="signInWithGooglePopup()" color="danger" class="btn-transition"> <strong class="white">Register/Login Google Popup Way</strong></ion-button> </ion-col> </ion-row> </ion-card-content> </ion-card> </div> </ion-content>
Login.page.ts:
import { auth } from 'firebase'; @Component({ selector: 'app-login', templateUrl: './login.page.html', styleUrls: ['./login.page.scss'], }) export class LoginPage implements OnInit { async signInWithGooglePopup(){ await this.auth.googleLoginPopup(); return await this.afterSignIn(); } private afterSignIn() { return this.router.navigate(['/']); } }
LoginService.ts:
LoginAuthService: This is where we tried hitting google service for oauth and stored the information’s in Plugins Storage(Something similar to Local storage in web applications).
import { Injectable } from '@angular/core'; import { AngularFireAuth } from '@angular/fire/auth'; import { User } from '../models/user'; import { BehaviorSubject } from 'rxjs'; import { Plugins } from '@capacitor/core'; @Injectable() export class LoginAuthService { private _user = new BehaviorSubject<User>(null); constructor(private afAuth: AngularFireAuth,){ } googleLoginPopup() { const provider = new auth.GoogleAuthProvider(); return this.oAuthLogin(provider); } private oAuthLogin(provider: any) { return this.afAuth.auth .signInWithPopup(provider) .then( credential => { let user = new User(); user.email = credential.user.email || null; user.userName = credential.user.uid; user.firstName = credential.user.displayName || 'Guest'; user.photoUrl = credential.user.photoURL || 'https://goo.gl/Fz9nrQ'; user.emailVerified = credential.user.emailVerified?"Y":"N"; user.src = 'FIREBASE-GOOGLE'; user.userRole = 'READER'; user.userStatus = 'ACTIVE'; credential.user.getIdToken() .then(token => { user.token = token; }).catch(error => { console.log("Error getting token:", error); }); this._user.next(user); // I have to store the user details in my api as well, if you dont have such requirement then comment the blow subscribe block this.userService.saveNewUser(user).subscribe( resp => { }, error => { console.log("Exception while saving user data after oauth"+error); }); Plugins.Storage.set({key:"googleOauthInfo", value:JSON.stringify(user)}); // this.notify.update('Welcome to Firestarter!!!', 'success'); }, error => { console.log("exception occured"+error); }); } }
signInWithRedirect Code Snippet:
Login.page.html:
<ion-row> <ion-col> <ion-button expand="block" (click)="signInWithGoogle()" color="danger" class="btn-transition"> <strong class="white">Register/Login with Google</strong></ion-button> </ion-col> </ion-row>
Login.page.ts:
import { auth } from 'firebase'; @Component({ selector: 'app-login', templateUrl: './login.page.html', styleUrls: ['./login.page.scss'], }) export class LoginPage implements OnInit { async signInWithGooglePopup(){ await this.auth.googleLoginPopup(); return await this.afterSignIn(); } private afterSignIn() { return this.router.navigate(['/']); } async signInWithGoogle() { await this.auth.googleLogin(); return awaitthis.afterSignIn(); } }
Login.service.ts
import { Injectable } from '@angular/core'; import { AngularFireAuth } from '@angular/fire/auth'; import { User } from '../models/user'; import { BehaviorSubject } from 'rxjs'; import { Plugins } from '@capacitor/core'; @Injectable() export class LoginAuthService { private _user = new BehaviorSubject<User>(null); constructor(private afAuth: AngularFireAuth,){ } /* below methods are redirection based google login authentications */ googleLogin() { const provider = new auth.GoogleAuthProvider(); this.oAuthGoogleLoginRedirect(provider); } private oAuthGoogleLoginRedirect(provider:any){ this.afAuth.auth.signInWithRedirect(provider).then(() => { // as this is the redirect one we wont get any response here, probably we will get in home component or profile component based on our redirection url schema configured in the google developer console }, error => { }); } /* Below methods are responsible for popup way google login */ googleLoginPopup() { const provider = new auth.GoogleAuthProvider(); return this.oAuthLogin(provider); } private oAuthLogin(provider: any) { return this.afAuth.auth .signInWithPopup(provider) .then( credential => { let user = new User(); user.email = credential.user.email || null; user.userName = credential.user.uid; user.firstName = credential.user.displayName || 'Guest'; user.photoUrl = credential.user.photoURL || 'https://goo.gl/Fz9nrQ'; user.emailVerified = credential.user.emailVerified?"Y":"N"; user.src = 'FIREBASE-GOOGLE'; user.userRole = 'READER'; user.userStatus = 'ACTIVE'; credential.user.getIdToken() .then(token => { user.token = token; }).catch(error => { console.log("Error getting token:", error); }); this._user.next(user); // I have to store the user details in my api as well, if you dont have such requirement then comment the blow subscribe block this.userService.saveNewUser(user).subscribe( resp => { }, error => { console.log("Exception while saving user data after oauth"+error); }); Plugins.Storage.set({key:"googleOauthInfo", value:JSON.stringify(user)}); // this.notify.update('Welcome to Firestarter!!!', 'success'); }, error => { console.log("exception occured"+error); }); } }
Generally redirection happens to particular url like ngdeveloper.com/home (based on our google developer console configuration) it is redirected to the particular page, and here is what we will get the complete details about the user who performed the logged in.
This block should be kept inside your component’s ionViewDidEnter() {} method, so that once the particular url has been accessed you will be able to get the redirected user details.
var message; this.aFAuth.auth.getRedirectResult().then(result => { if(result){ if (result.credential) { //var token = result.credential.p; } // getting the logged in user details here if(result.user){ let user = new User(); user.email = result.user.email || null; user.userName = result.user.uid; user.firstName = result.user.displayName || 'Guest'; user.photoUrl = result.user.photoURL || 'https://goo.gl/Fz9nrQ'; user.emailVerified = result.user.emailVerified?"Y":"N"; user.src = 'FIREBASE-GOOGLE'; user.userRole = 'SUBSCRIBER'; user.userStatus = 'ACTIVE'; result.user.getIdToken() .then(token => { user.token = token; }) .catch(error => { console.log("Error getting token:", error); }); this.auth.setValues(user, result.user); // if you want to save in your api this.userService.saveNewUser(user).subscribe( resp => { }, error => { console.log("Exception while saving user data after oauth"+error); }); Plugins.Storage.set({key:AppSettings.USER_LOGIN_META_INFO_COOKIE, value:JSON.stringify(user)}); message = "success"; } else { message = "no user"; } } else { message = "didnt work"; } this.showAlert(message); //stack flow test }).catch(function(error) { var errorCode = error.code; var errorMessage = error.message; var email = error.email; var credential = error.credential; message = "error with getRedirectResult"; this.showAlert(message); //stack flow test });
Google Oauth Login + Ionic 4 Implementation is well explained in the medium posts.
Feel free to post your comments below.