Published on April 13, 2021
Last Revised on July 24, 2021
This series of posts describes one way to add user authentication to an Angular application using Auth0 and Firebase with the help of AWS Lambda.
This guide shows one way to integrate Auth0, AWS Lambda, and Google Firebase together into the authentication of an Angular app. It is not a complete, polished, production-ready authentication solution, however you will learn a way to:
Let's get started!
I created a repo for a simple Angular starter app that contains placeholders for the integrations that we will be completing throughout this guide. To get started, clone the starter
branch of the repository:
git clone -b starter --single-branch https://github.com/RichTillis/ng-auth0-lambda-firebase-demo.git
cd ng-auth0-lambda-firebase-demo/
Next, install all the dependencies and startup the app to take a look at what's going on.
npm install && ng serve -o
This guide focuses on the integration of external services so we will keep the UI simple and use this basic three-button Angular app. The idea beind the UI is that each button becomes enabled once the prior step in the authentication process is successfully completed.
These behaviors are mocked out in the app so try it out. src/app/services/auth.service.ts
maintains the state of the authentication progress. app.component.ts
has the Auth service injected and references the Observables which stream any of change of state to their subscribers. The app template, app.component.html
, subscribes to these and updates via the | async
as the authentication state changes.
Use ctrl
+c
keys to stop the app.
Dan Arias of Auth0 wrote The Complete Guide to Angular User Authentication with Auth0 that really is the complete Auth0 guide. I learned a great deal from it and much of this section comes from Dan's writing. All credit to Dan.
NG-Conf & the Auth0 Dev Rel team posted has a great walkthrough guide called Authentication & Authorization in Angular with Auth0 on YouTube
Log into Auth0. Once logged in, you will arrive at your account dashboard. From your dashboard, click on the Applications sub menu item in the left-hand navigation menu.
The main content will display all of your existing appliations if you have any. Click on the Create Application button.
In the subsequent Create application modal, name your app and select the Single Page Web Applications application type. For this tutorial I will name the app ng-aws-firebase-auth-app
. Click the Create button to create the app.
Once the app is created you will be routed to that application. Click on the Settings tab. In the Basic Information section, copy down the Domain and the Client ID and keep them somewhere close by. We will need them shortly.
In the Application URIs section, update Allowed Callback URLs, Allowed Logout URLs, and Allowed Web Origins with http://localhost:4200. Be aware that localhost:4200 is only being used for development. When you app make it to a production environment you will need to add the location (IP address) and port where your app is being hosted. Click the Save Changes button at the bottom of the page.
All done setting up the Auth0 app.
Open the Angular app. First thing we want to do is update the /tsconfig.json
file and add "resolveJsonModule": true
. This setting will allow us to import .json
files into the app's TypeScript modules.
// tsconfig.json
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"module": "es2020",
"lib": [
"es2018",
"dom"
],
"resolveJsonModule": true // <-- Add this
},
"angularCompilerOptions": {
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
Create a file at the root of the Angular project and name it auth0-config.json
. In this file you will use the Auth0 domain and client Id that we copied during the Auth0 app setup.
// auth0-config.json
{
"domain": "#####-######.auth0.com", // <-- Change this
"clientId": "1234567890aBcDeFgHiJkLmNoPqRsTuV" // <-- Change this
}
We can use that file's contents thanks to the resolveJsonModule
flag we previously set. So update the src/environments/environments.ts
file accordingly.
// environments.ts
import { domain, clientId } from '../../auth0-config.json';
export const environment = {
production: false,
auth: {
domain,
clientId,
redirectUri: window.location.origin,
}
};
Now we will add the Auth0 SDK. From the terminal we can do that using Angular schematics:
ng add @auth0/auth0-angular
With the Auth0 library now available to the project, we need to import it and load the module in src/app/app.module.ts
.
// app.module.ts
// ... All the existing imports are here...
// add these
import { AuthModule as Auth0Module } from '@auth0/auth0-angular';
import { environment as env } from '../environments/environment';
@NgModule({
declarations: [
AppComponent
],
imports: [
// ... All the existing imports are here ...
// ... load the Auth0 module
Auth0Module.forRoot({...env.auth})
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Auth0 is now bootstrapped to the app. The next step is to use it. The Auth0 SDK is going to perform all the Auth0 specific authentication activities and report back to the Angular app with the results of the authentication attempt. We to want wrap this library into the app's existing Auth service
.
Update src/app/services/auth.service.ts
with the following changes
// auth.service.ts
import { Injectable, Inject } from '@angular/core';
//add this import
import { DOCUMENT } from '@angular/common';
import { BehaviorSubject, Observable } from 'rxjs';
// add this
import { AuthService as Auth0Service } from '@auth0/auth0-angular';
@Injectable({
providedIn: 'root'
})
export class AuthService {
// remove auth0UserSubject
// private auth0UserSubject$: BehaviorSubject<any> = new BehaviorSubject<any>(undefined);
// replace auth0User$ assignment
readonly auth0User$ = this.auth0Service.user$;
private firebaseTokenSubject$: BehaviorSubject<string | undefined> = new BehaviorSubject<string | undefined>(undefined);
readonly firebaseToken$: Observable<any> = this.firebaseTokenSubject$.asObservable();
private firebaseUserIdSubject$: BehaviorSubject<string | undefined> = new BehaviorSubject<string | undefined>(undefined);
readonly firebaseUserId$: Observable<string | undefined> = this.firebaseUserIdSubject$.asObservable();
// update the constructor
constructor(private auth0Service: Auth0Service, @Inject(DOCUMENT) private doc: Document) { }
// update this method
loginToAuth0(): Observable<void> {
return this.auth0Service.loginWithRedirect();
}
// add this method
private logoutOfAuth0() {
this.auth0Service.logout({ returnTo: this.doc.location.origin });
}
getTokenFromLambda() {
this.firebaseTokenSubject$.next("MyPretendToken_ABCD123EFG456");
}
loginToFirebase() {
this.firebaseUserIdSubject$.next("Pretend_Firebase_user");
}
// update this method
logout() {
this.logoutOfAuth0();
this.firebaseTokenSubject$.next(undefined);
this.firebaseUserIdSubject$.next(undefined);
}
logoutOfFirebase(){
this.firebaseTokenSubject$.next(undefined);
this.firebaseUserIdSubject$.next(undefined);
}
}
That's it. Auth0 should be wired in. Moment of truth. Start up the app and login/signup to Auth0.
ng serve -o
If everything went as planned, once you click on the Login to Auth0 button, an Auth0 modal will pop-up requesting login.
Finally, once you have authenticated using Auth0, your Auth0 user name will be displayed under the Logout of Auth0 button.
Congrats - Part 1 is complete!!
In this post, we setup our Angular app, as well as an Auth0 application, and integrated Auth0 authentication into the Angular app. In Part 2 of this guide we will setup a Google Firebase project and integrate it into the app. Stay Tuned!