Skip to content

Instantly share code, notes, and snippets.

@jingyuyao
Last active June 12, 2018 06:37
Show Gist options
  • Save jingyuyao/c08b7066f8ac0e506716ce6cce5bc5a7 to your computer and use it in GitHub Desktop.
Save jingyuyao/c08b7066f8ac0e506716ce6cce5bc5a7 to your computer and use it in GitHub Desktop.
Angular 6 Google sign-in
<button
*ngIf="isSignedIn$ | async"
(click)="logOut()">
Logout
</button>
<div id="google-signin" [hidden]="isSignedIn$ | async"></div>
<span *ngIf="isSignedIn$ | async; else notSignedIn">
Current user: {{(currentUser$ | async).getBasicProfile().getName()}}
</span>
<ng-template #notSignedIn>
<span>Not signed in</span>
</ng-template>
import { Component, OnInit, AfterViewInit } from '@angular/core';
import { Observable } from 'rxjs';
import { IdentityService } from './identity.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
currentUser$: Observable<gapi.auth2.GoogleUser>;
isSignedIn$: Observable<boolean>;
constructor(private identityService: IdentityService) { }
ngOnInit() {
this.currentUser$ = this.identityService.currentUser$;
this.isSignedIn$ = this.identityService.isSignedIn$;
}
ngAfterViewInit() {
this.identityService.render('google-signin');
}
logOut() {
this.identityService.logOut();
}
}
import { Injectable, NgZone } from '@angular/core';
import { ReplaySubject } from 'rxjs';
import { map } from 'rxjs/operators';
/**
* Handles integration with Google sign-in. Exposes functionalities as observables.
* Fails silently when the API could not be loaded or when third-party cookies are blocked.
*
* References:
* - https://stackoverflow.com/a/42782430
* - https://stackoverflow.com/a/50616780
*/
@Injectable({
providedIn: 'root'
})
export class IdentityService {
private static readonly CLIENT_ID = 'YOUR_CLIENT_ID.apps.googleusercontent.com';
private static readonly SCOPE = 'profile email openid';
currentUser$ = new ReplaySubject<gapi.auth2.GoogleUser>(1);
isSignedIn$ = this.currentUser$.pipe(map(user => user.isSignedIn()));
private auth2$ = new ReplaySubject<gapi.auth2.GoogleAuth>(1);
constructor(private zone: NgZone) {
if (gapi) {
gapi.load('auth2', {
callback: () => {
const auth2 = gapi.auth2.init({
client_id: IdentityService.CLIENT_ID,
scope: IdentityService.SCOPE,
});
auth2.currentUser.listen(
user => this.zone.run(() => this.currentUser$.next(user)));
this.zone.run(() => {
this.auth2$.next(auth2);
this.auth2$.complete();
});
},
onerror: () => this.zone.run(() => {
console.error('unable to load gapi.auth2');
this.auth2$.complete();
}),
});
} else {
console.error('gapi does not exist');
this.auth2$.complete();
}
}
render(elementId: string) {
this.auth2$.subscribe(() => gapi.signin2.render(elementId, {
scope: IdentityService.SCOPE,
}));
}
logOut() {
this.auth2$.subscribe(auth2 => {
auth2.signOut();
});
}
}

Install typings

npm install --save @types/gapi
npm install --save @types/gapi.auth2

Add typing to tsconfig.app.json

"compilerOptions": {
  ...
  "types": ["gapi", "gapi.auth2"],
  ...
}

Load platform.js in index.html

<head>
  ...
  <!-- Notice there is no 'async' or 'defer' -->
  <script src="https://apis.google.com/js/api.js"></script>
</head>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment