This article is a simple guide on how to implement google api in angular and how to integrate a user session with a firebase service.

Step 1: Create Angular project

  1. Install Angular CLI.
    npm install -g @angular/cli
  2. Create new angular project.
    ng new firebase-auth-via-google-api-example
  3. Go to project directory.
    cd firebase-auth-via-google-api-example
  4. Install the required dependencies.
    npm install --save firebase @angular/fire
    npm install --save-dev @types/gapi @types/gapi.auth2 @types/gapi.client

Step 2: Create Firebase project

  1. Go to https://console.firebase.google.com/
  2. Create new project.
  1. Enable Google sign-in in Authentication.
  1. Add a web app

Copy firebase config to src/environments/environment.ts.

export const environment = {
  ...
  firebase: {
    apiKey: "AIzaSyCq9YuvCvVkjdQrhm3hFTQboI2CV_SZnqI",
    authDomain: "api-example-e267d.firebaseapp.com",
    databaseURL: "https://api-example-e267d.firebaseio.com",
    projectId: "api-example-e267d",
    storageBucket: "api-example-e267d.appspot.com",
    messagingSenderId: "687667050591",
    appId: "1:687667050591:web:695d797c2e266a7c"
  }
};

Step 3: Setup Google API project

  • Open OAuth 2.0 client IDs - Web client (auto created by Google Service)
    Add http://localhost:4200/ to Restrictions - Authorized Javascript origins
  • Set email in OAuth consent screen.

  • Copy client ID to src/environments/environment.ts

export const environment = {
  ...
  firebase: {
    apiKey: "AIzaSyCq9YuvCvVkjdQrhm3hFTQboI2CV_SZnqI",
    authDomain: "api-example-e267d.firebaseapp.com",
    databaseURL: "https://api-example-e267d.firebaseio.com",
    projectId: "api-example-e267d",
    storageBucket: "api-example-e267d.appspot.com",
    messagingSenderId: "687667050591",
    appId: "1:687667050591:web:695d797c2e266a7c",
    clientId: "687667050591-56og5jl7jah8ijg9ukft5ihbumacqash.apps.googleusercontent.com"
  }
};

Step 4: Create the necessary services and components in angular project

  • Go to angular project.
  • Create Google API service.
    ng generate service GAPI
    Copy to src/app/gapi.service.ts

    /// <reference path="../../node_modules/@types/gapi/index.d.ts" />
    /// <reference path="../../node_modules/@types/gapi.auth2/index.d.ts" />
    /// <reference path="../../node_modules/@types/gapi.client/index.d.ts" />
    
    import { Injectable } from '@angular/core';
    import { Observable, Observer } from 'rxjs';
    import { environment } from 'src/environments/environment';
    
    @Injectable({
      providedIn: 'root'
    })
    export class GAPIService {
      private readonly url: string = 'https://apis.google.com/js/api.js';
      private loaded = false;
    
      private loadGapi(): Observable<void> {
        return new Observable((observer: Observer<void>) => {
          if (this.loaded) {
            observer.next();
            observer.complete();
            return;
          }
          const node = document.createElement('script');
          node.src = this.url;
          node.type = 'text/javascript';
          document.getElementsByTagName('head')[0].appendChild(node);
          node.onload = () => {
            this.loaded = true;
            observer.next();
            observer.complete();
          };
          node.onerror = (error) => {
            observer.error(error);
          };
        });
      }
    
      public async initClient(baseScopes: string[] = ['email']) {
        await this.loadGapi().toPromise();
        return new Promise<void>(async (resolve, reject) => {
          try {
            const initClient = async (error) => {
              if (error) {
                return reject(error);
              }
              try {
                await gapi.client.init({
                  apiKey: environment.firebase.apiKey,
                  clientId: environment.firebase.clientId,
                  scope: baseScopes.join(' ')
                });
                return resolve();
              } catch (error) {
                return reject(error);
              }
            }
            gapi.load('client:auth2', initClient);
          } catch (error) {
            return reject(error);
          }
        });
      }
    }
    
    
  • Create Google Authentication service.
    ng generate service google-auth
    Copy to src/app/google-auth.service.ts

    import { Injectable, NgZone } from '@angular/core';
    import { AngularFireAuth } from '@angular/fire/auth';
    import { environment } from 'src/environments/environment';
    import { auth } from 'firebase/app';
    import { Observable, ReplaySubject } from 'rxjs';
    import { GAPIService } from './gapi.service';
    import * as firebase from 'firebase';
    
    @Injectable({
      providedIn: 'root'
    })
    export class GoogleAuthService {
      private isLoggedIn$ = new ReplaySubject<boolean>(1);
      private user$ = new ReplaySubject<firebase.User>(1)
    
      constructor(public afAuth: AngularFireAuth, public gapiService: GAPIService, private ngZone: NgZone) {
        this.isLoggedIn$.next(false);
        this.afAuth.auth.onAuthStateChanged(async (user) => {
          this.ngZone.run(() => {
            this.isLoggedIn$.next(Boolean(user));
            this.user$.next(user);
          })
        });
      }
    
      get isLoggedIn(): Observable<boolean> {
        return this.isLoggedIn$.asObservable();
      }
    
      get user(): Observable<firebase.User> {
        return this.user$.asObservable();
      }
    
      async signOut(): Promise<void> {
        return auth().signOut();
      }
    
      private async initAuth2(baseScopes: string[]): Promise<void> {
        await this.gapiService.initClient(baseScopes);
        if (!gapi.auth2.getAuthInstance()) {
          gapi.auth2.init({
            client_id: environment.firebase.clientId,
            scope: baseScopes.join(' ')
          });
        }
      }
    
      async signIn(baseScopes: string[] = ['email']): Promise<void> {
        await this.initAuth2(baseScopes);
        const googleUser = await gapi.auth2.getAuthInstance().signIn({
          prompt: 'select_account'
        });
        const token = googleUser.getAuthResponse().id_token;
        const credential = auth.GoogleAuthProvider.credential(token);
        await auth().signInAndRetrieveDataWithCredential(credential);
      }
    }
    
    
  • Create login component.
    ng generate component google-sign-in
    Copy to src/app/google-sign-in/google-sign-in.component.html

    <ng-container *ngIf="user$ | async as user; else loggedOut">
      <span>{{ user.displayName }}</span>
      <img class="user-photo" src="{{ user.photoURL }}">
      <a (click)="logout()">Logout</a>
    </ng-container>
    <ng-template #loggedOut>
      <a (click)="login()">Login</a>
    </ng-template>
    

    Copy to src/app/google-sign-in/google-sign-in.component.ts

    import { Component, OnInit } from '@angular/core';
    import { GoogleAuthService } from '../google-auth.service';
    import * as firebase from 'firebase';
    import { Observable } from 'rxjs';
    
    @Component({
      selector: 'app-google-sign-in',
      templateUrl: './google-sign-in.component.html',
      styleUrls: ['./google-sign-in.component.scss']
    })
    export class GoogleSignInComponent {
      user$: Observable<firebase.User>;
    
      constructor(
        private googleAuth: GoogleAuthService
      ) {
        this.user$ = this.googleAuth.user;
      }
    
      login() {
        this.googleAuth.signIn();
      }
    
      logout() {
        this.googleAuth.signOut();
      }
    
    }
    
  • Add AngularFireModule and AngularFireAuthModule to src/app/app.module.ts

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    
    import { AppRoutingModule } from './app-routing.module';
    import { AppComponent } from './app.component';
    import { GoogleSignInComponent } from './google-sign-in/google-sign-in.component';
    import { AngularFireModule } from '@angular/fire';
    import { environment } from 'src/environments/environment';
    import { AngularFireAuthModule } from '@angular/fire/auth';
    
    @NgModule({
      declarations: [
        AppComponent,
        GoogleSignInComponent
      ],
      imports: [
        BrowserModule,
        AppRoutingModule,
        AngularFireModule.initializeApp(environment.firebase),
        AngularFireAuthModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    
    

    Add <app-google-sign-in> to src/app/app.component.html

    <div style="text-align:center">
      <app-google-sign-in></app-google-sign-in>
    </div>
    

Step 5: Test application authorization

That’s all, now you can extend the capabilities of the application with all the possibilities of google apis and firebase.

The repository of the entire example described in this article is on github.
https://github.com/studioLaCosaNostra/firebase-auth-via-google-api-example

If you have any problems in any of the steps of this guide, please write in a comment about it.
I will try to write back and refine the article. :)