User authentication is a critical component of many web applications. With Firebase, integrating user login features becomes a breeze, especially when using Angular with AngularFire. This guide will walk you through the steps to authenticate users using Google Sign-In, save custom user data to Firestore, and create a router guard to secure certain routes. Let’s get started!
Why Use Firebase Authentication?
Firebase offers a robust and easy-to-implement authentication service that supports multiple login methods, including email/password logins, social media logins (like Google, GitHub, and Facebook), and more. By incorporating Firebase Authentication with Firestore, you can not only secure user access but also store relevant user information in real-time.
Prerequisites
Before diving into the implementation, ensure you have the following:
- A Firebase account with Google login provider enabled.
- An existing Angular project with AngularFire installed (version 5 or higher).
If you’re new to AngularFire, follow the setup instructions found in the AngularFire documentation.
Setting Up the Project
Creating a Core Module
To keep your application organized, create a core module that will be responsible for handling global services like authentication. This module is optional but highly recommended. Here’s how you can do that:
- Generate the core module using Angular CLI.
- Import it into the app module.
Adding AngularFire Services
Next, you need to add AngularFire authentication services and Firestore services to your core module. Here’s a simple structure:
import { AngularFireAuthModule } from '@angular/fire/auth';
import { AngularFirestoreModule } from '@angular/fire/firestore';
@NgModule({
imports: [
AngularFireAuthModule,
AngularFirestoreModule
],
})
export class CoreModule {}
Creating an Authentication Service
Now, create an authentication (Auth) service:
- Generate the service named
auth.service.ts
. - Implement the necessary AngularFire modules and an Observable to handle user authentication.
Here’s a sample implementation:
import { Injectable } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/auth';
import { AngularFirestore } from '@angular/fire/firestore';
import { Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class AuthService {
user$: Observable<User | null>;
constructor(private afAuth: AngularFireAuth, private afs: AngularFirestore) {
this.user$ = this.afAuth.authState.pipe(
switchMap(user => {
if (user) {
return this.afs.doc<User>(`users/${user.uid}`).valueChanges();
} else {
return [null];
}
})
);
}
loginGoogle() {
const provider = new firebase.auth.GoogleAuthProvider();
return this.afAuth.signInWithPopup(provider);
}
// More methods can go here...
}
Saving Custom User Data
In the authentication service, after the user successfully logs in, save their data in Firestore. You might want to capture additional attributes such as favorite color or user preferences. Here’s how to do that:
private createUserDocument(user: User) {
const userRef: AngularFirestoreDocument<User> = this.afs.doc(`users/${user.uid}`);
const data: User = {
uid: user.uid,
email: user.email,
displayName: user.displayName,
favoriteColor: user.favoriteColor || null
};
return userRef.set(data, { merge: true });
}
Building the User Profile Component
Generating the Component
Generate a component named user-profile
where you will display user information:
- Use Angular CLI to create the component.
- Inject the
AuthService
into the component’s constructor.
Handling User Authentication
You’ll want to conditionally display content based on whether the user is authenticated. Use Angular directives like *ngIf
for this purpose:
<div *ngIf="authService.user$ | async as user; else guest">
<h1>Welcome, {{ user.displayName }}</h1>
<p>Your favorite color: {{ user.favoriteColor }}</p>
</div>
<ng-template #guest>
<button (click)="authService.loginGoogle()">Login with Google</button>
</ng-template>
Implementing a Router Guard
To protect certain routes from unauthorized users, create a router guard:
- Generate the guard using Angular CLI.
- Implement the logic to check user authentication.
Here’s a sample structure for the guard:
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService, private router: Router) {}
canActivate(): Observable<boolean> {
return this.auth.user$.pipe(
take(1),
map(user => {
if (user) {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
})
);
}
}
Once implemented, you can apply this guard to your routes in the Angular router configuration.
Conclusion
Integrating Google Sign-In with Firestore for managing custom user data in Angular is a straightforward yet powerful process. By following these steps, you can ensure that your application has a robust authentication system — one that securely manages user data and prevents unauthorized access to critical routes.
If you found this guide helpful and you’re interested in exploring more advanced features of Firebase with Angular, check out relevant resources or consider becoming a pro member of AngularFire.
Don’t forget to subscribe for updates and enhancements to your application!