Using SuperTokens with Angular and Firebase

Part III: Setting up the application

--

This post is the third of my four-part series:

Overview

My aim is to help those who have an existing application with the integration of SuperTokens. For that purpose, I will take start from a fresh Angular application that includes AngularFire and Angular Material. The application will use standalone components, which is new in Angular 14.

The application will use the pre-built UI provided by SuperTokens, and integrate the SuperTokens frontend and backend. For the core, we will use the managed service as the SuperTokens core.

We will also set up a local development environment using the Firebase Emulators.

You can follow the step-by-step process in this GitHub repository. The commits roughly follow the various steps described here.

Step 1 — Install Angular

Install an Angular 14 template project using the Angular CLI including Angular Routing and using SCSS.

npm install -g @angular/cli
ng new supertokens-demo-1

This will create a generic Angular stub application, which we will use as the basis for the subsequent steps. You can confirm that all is well by running the application locally:

npm run start

Step 2 — Install AngularFire

Next, we will install AngularFire. Be sure to include Authentication, Firestore, and Cloud Functions.

ng add @angular/fire

Additional instructions are available on the AngularFire GitHub page.

At this juncture, we will change the original project stub to use the new Angular 14 feature of standalone components. This commit shows the changes I made.

At this point, it may be wise to again confirm that everything is still running as expected.

npm run start

Step 3 — Install the Firebase Emulators

For now, we only want to use the data locally in our development environment. The purpose of this demo is to show how to use SuperTokens with Angular and Firebase, and doing so locally with the emulators is sufficient.

We will follow the instructions for installing the Emulator Suite. First, initialize Firestore, being sure to include Firestore, Functions, and Emulators. We will use Typescript and include eslint. For the rest, use the defaults when prompted.

firebase init

When prompted to configure the Emulators, be sure to again include Authentication, Functions, and Firestore. Use default ports, and enable the UI emulator.

To use data locally with the Emulators, use this command:

firebase emulators:start --import data --export-on-exit

To ensure that we can access Firebase Functions from the Emulator, uncomment the example in functions/src/index.ts. Build the functions:

cd functions
npm run build

Now ensure that the Emulators can run and you can view the Emulator UI in your browser. Also ensure that the application is still working as expected.

Step 4— Connect to Firestore

We are now going to remove the default Angular application stub and begin to create our own application code. The code for this step is shown in this commit. I will provide a brief explanation here, but it is better to follow along in the code. I am assuming that you already know how to create components and services in Angular.

Initially, we will set up a simple collection of items in Firestore, and leave the data unprotected. We will deal with authorization later. For now, we only want to ensure that we can connect to Firestore without any issues.

Here are the actions to take in a nutshell:

  • Remove the default application code in the ApplicationComponent
  • Add a HomeComponent on the root route
  • Add an ItemsComponent on the route ‘items’
  • Add a PageNotFoundComponent as a catch-all on ‘**’
  • Add an ItemsService to connect to Firestore

For demo purposes, we will use this very simple object:

export interface Item {
id: string;
name: string;
}

As usual, ensure that the application is running and you can connect and view the items stored in Firestore.

Step 5— Create a Backend API with Firebase Functions

In some cases we will connect directly to Firestore, but in others we still need to access a backend API. The API will also be protected by SuperTokens, but we first need to set it up.

I am told that everybody likes cats, so we will use a backend that presents Cat Facts. For the purpose of demonstrating SuperTokens, our backend will just be a simple proxy that fetches a cat fact and serves it to our application. For now, it will not be protected.

The code is in this commit. I added a Cats service and a Cats component on the frontend, and the following Firebase Function on the backend:

export const cats = functions.https.onRequest(async (request, response) => {
try {
const resp = await axios.get('https://catfact.ninja/fact');
response.set('Access-Control-Allow-Origin', `http://localhost:${localhostApiPort}`);
response.status(200).json(resp.data);
} catch (error) {
response.status(400).json(`{error: ${error}}`);
}
});

I have learned a lot about cats already. 🤣

Step 6— Install Angular Material

For the final step, we will install Angular Material, improve the look and feel a little bit, and fix up a few things. Somehow, the app turned into an app about cats. 🤷‍♂️ The point here is to make a consistent and working, albeit completely useless app, unless of course, you really, really love cats and need a rudimentary cat tracker app.

Using the Material Toolbar, we will later be able to show how the authentication state communicated by SuperTokens affects application components.

As the final result, you should see a home screen like this:

The cat tracker screen looks like this:

Finally, the cat fact screen:

Alright, maybe I went a bit crazy with the cat theme. I don’t even own a cat!

In the next article, we will finally add authentication and authorization using SuperTokens.

--

--

David Leangen | Entrepreneur & Software Engineer

Business-oriented engineer & technically oriented executive and entrepreneur. I apply technology to help small businesses thrive.