I have set up a new angular 6 project with Firebase auth and Cloud Fire Store. There is a login page where you can login via google and the user data is saved in Firestore (code below). My only issue is how I can check if the user is already logged in, is there any best practice?
At the moment im fetching the user data async, but then the navigation is flickering. For one second there is the login button, then it switches to the logout button. Is there good way to check the login state before it renders the page?
User.ts
export interface User {
uid: string;
email: string;
}
auth.service.ts
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import * as firebase from 'firebase/app';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFirestore, AngularFirestoreDocument } from 'angularfire2/firestore';
import { Observable, of } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { User } from './user';
@Injectable({
providedIn: 'root'
})
export class AuthService {
user: Observable<User>;
constructor(private afAuth: AngularFireAuth, private afs: AngularFirestore, private router: Router) {
this.user = this.afAuth.authState.pipe(
switchMap(user => {
if (user) {
return this.afs.doc<User>(`users/${user.uid}`).valueChanges();
} else {
return of(null);
}
}))
}
public googleLogin() {
const provider = new firebase.auth.GoogleAuthProvider()
return this.oAuthLogin(provider);
}
public signOut() {
this.afAuth.auth.signOut();
}
private oAuthLogin(provider) {
return this.afAuth.auth.signInWithPopup(provider)
.then((credential) => {
this.updateUserData(credential.user)
})
}
private updateUserData(user) {
const userRef: AngularFirestoreDocument<any> = this.afs.doc(`users/${user.uid}`);
const data: User = {
uid: user.uid,
email: user.email
}
return userRef.set(data, { merge: true })
}
}
navigation.component.ts
import { Component, OnInit } from '@angular/core';
import { AuthService } from '../core/auth.service';
import { AngularFireAuth } from 'angularfire2/auth';
@Component({
selector: 'app-navigation',
templateUrl: './navigation.component.html',
styleUrls: ['./navigation.component.scss']
})
export class NavigationComponent implements OnInit {
constructor(public auth: AuthService) { }
ngOnInit() {}
}
auth.service.ts
<div *ngIf="auth.user | async; then loggedIn else loggedOut"></div>
<ng-template #loggedOut>
<li class="nav-item d-none d-md-inline-block pl-2 pr-0">
<a class="btn btn-sm btn-primary u-btn-primary u-btn-pill transition-3d-hover" href="/login">
Login
</a>
</li>
</ng-template>
<ng-template #loggedIn>
<li class="nav-item d-none d-md-inline-block pl-2 pr-0">
<a class="btn btn-sm btn-primary u-btn-primary u-btn-pill transition-3d-hover" (click)="auth.signOut()">
Logout
</a>
</li>
</ng-template>
You probably figured this out a long time ago but someone else might wonder. I chose to do a check against the authState of angularFireAuth. If it's null, then you're logged out. Then You can use route guards as explained in Ryan Chenkie's Medium article
@Injectable()
export class FirebaseAuthService {
private authState: Observable<firebase.User>
private currentUser: firebase.User = null;
constructor(
public afAuth: AngularFireAuth,
private http: HttpClient,
private localStorage: LocalStorageService,
private router: Router,
private snackBar: MatSnackBar) {
this.authState = this.afAuth.authState;
this.authState.subscribe(user => {
if (user) {
this.currentUser = user;
this.localStorage.storeSimple('userData', user)
this.openSnackBar('Successfully authenticated');
console.log('AUTHSTATE USER', user)
this.router.navigate(['home']);
} else {
console.log('AUTHSTATE USER EMPTY', user)
this.currentUser = null;
}
},
err => {
this.openSnackBar(`${err.status} ${err.statusText} (${err.error.message})`, 'Please try again')
});
}
isAuthenticated(): boolean {
return this.authState !== null;
}
loginEmail(email, password, route) {
this.afAuth.auth.signInWithEmailAndPassword(email, password).catch(error => {
let errorCode = error.code;
let errorMessage = error.message;
this.openSnackBar(error, 'OK')
});
}
logout() {
this.afAuth.auth.signOut()
.then(response => this.openSnackBar('Signed out'))
.catch(error => this.openSnackBar('Error signing out: ' + error));
}
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With