Angular is a Typescript SPA framework that leads to well-architected applications
In this article, we will be looking at the following aspects of the Angular frontend:
- High-level architecture
- Auth0 setup
- HTTP Interceptors that attach a JWT token to every request to the API backend
- How to use the Auth0 SDK to control the user’s experience based on whether they’re logged in
- How to invoke the backend API
The source code for the frontend is available here.
The Feedback Pal UI has four modules:
- The AppModule. This is the entry point for all Angular applications
- The Smiley Module. This module is in charge of rendering the Smiley Cards, which users use to send feedback, after selecting an event. This is a lazy module. What this means is that the browser will download the module only when it’s required.
- The FeedbackEvents Module. This is also a lazy module. This module is in charge or rendering and managing everything that has to do with FeedbackPal events.
- The MyFeedbackpal Module. This is also a lazy module. This module is in charge of rendering and managing all the capabilities under the “My Feedbackpal” dropdown module.
- The Shared Module. This module is loaded eagerly and it contains reusable assets (components, models, services) that other modules can use.
Setting up Auth0
In this section we’ll go through how I’ve secured the Feedback Pal frontend with Auth0. I assume that you have cloned the repository and you will be able to follow by looking at the code.
Create the Auth0 configuration files
The first thing to do is to create two Auth0 configuration files: one for dev and one for prod. As we will see later, during build time, we’ll tell Angular which one to pick.
Create the following two files at the root of your project:
You can name these two files what you want. They will be identical in their structure although the values will change.
This file contains the following information required by Auth0:
- domain. This is the “domain” value stored in the Auth0 application setup. Please refer to this page to remind yourself how to setup Auth0 for your frontend.
- clientId. Still from the Application setup in Auth0, this is the value of the Client ID
- audience. This is the Identifier value in your API setup for Auth0. Please refer to this page to remind yourself how to setup an API in Auth0. In a nutshell, when users authenticate on the frontend they get an ID Token. This needs to be exchanged for a JWT token when invoking an API backend. The role of the audience is to tell Auth0 which API setup should be considered when asking for (in our case) JWT tokens.
- serverUrl. This is the URL to the API backend. For development, since I’m running locally on port 3000, the URL is http://localhost:3000. For production the URL points to the API backend production instance
The Production configuration
Setting up the environments
Now that we have the Auth0 configuration, we can set up the Angular environment files. Environment files sit under the src folder. In Feedback Pal, there are two environment files:
- environment.ts. This is the file that ultimately will be shipped with every deployment.
- environment.prod.ts. This is the file that when we build the application with the “production” configuration will be copied as environment.ts.
The dev configuration
There are three pieces of information which are important here:
- As you can see, as this file is used for development as default configuration, we import the auth_config.json file that we have set up earlier, which is also a dev configuration.
- The production element is set to false]
- Finally, we set the value of the auth and api objects with values taken from the Auth0 configuration file. The application will later make use of this file by importing the environment into components.
The production configuration
The file structure is identical to the dev one (as it should be), however there are two important differences:
- Here we import the production Auth0 configuration. Therefore the values for the different properties here will change with the values contained in this file
- The second is that we set production to true.
How do we tell Angular which file to use?
If you look at the angular.json file in the root of your project, you will notice the following entry:
When we build the SPA application with the –production configuration, Angular will replace the environment.ts file with the content from the environment.prod.ts. Of course you can have any number of configurations for different environments. All you have to do is to update the angular.json file accordingly.
Installing the Auth0 SDK
In order for our client app to use Auth0, we need to do few things:
- Install the Auth0 SDK with the following command:
npm install @auth0/auth0-angular
- Configure Auth0 in your AppModule (in the app.module.ts file)
The picture above shows the configuration of the Auth0 module in the app.module.ts file. We need to import the environment (this will always be correct, containing dev or prod values depending on how we build the resulting app). In the forRoot function, we bring in all values for the auth object, as well as the value for api.serverUrl, which contains the URL to the backend API. Finally, we set a HTTP interceptor, saying that for every request going out to the API, the interceptor should generate a JWT token and set it in the Authorization header with the following format: Authorization Bearer <JWT token>. You can be specific about the URLs you want to HTTP intercept to send the JWT token to. In the Feedback Pal case, I want all calls to the API backend to be protected, therefore I set the wildcard ‘*’ after the API url.
To complete the Auth0 setup in the AppModule, you also need to setup the HTTP Interceptor (as briefly mentioned above).
Setting up the Angular Auth0 Guard
With the setup so far, we have available the Auth0 AuthService which we can inject in our components and services to check, for instance, whether a user is logged in. The way to do this in Angular is to create a Guard. Guards are used to protect access to resources.
Auth0 provides an Angular Guard
The good news is that Auth0 provides a Guard to protect routes. Let’s see how to use this in our Angular frontend.
Feedback Pal uses modules with routing. Above it’s the setup I use to protect all requests routed to “/feedback”. The strange syntax above is how in Angular one manages Lazy Loaded Modules. In this case, the SmileyModule is lazily loaded upon request.
The way we protect access to a route is by using the canActivate property of a Route configuration, indicating the AuthGuard Guard that Auth0 provides.
With this simple setting, every time a user tries to visit /feedback, the Guard will kick in, check whether the user is authenticated and if not, the Auth0 Login Box will be presented for users to login.
Displaying frontend components dynamically
Access to protected routes is not the only functionality we can benefit from by using the Auth0 SDK. We can also display or hide content on the page using the Auth0 SDK. For example, the initial Feedback Pal home page looks like the following:
The NavBar Typescript component
Having a look at the NavBar Typescript component, we can see that the Auth0Service is injected in the constructor as a public property, making it available to the html for the component.
Now, from the html code for the NavBar, we can write code like the following:
I’ve created a component for each of the buttons. In the picture above you can see conditional logic for each of the buttons:
- If the user is not logged in, we display the Login (<app-login-button>) and the Signup <app-signup-button>) buttons
- If the user is logged in, we display the Logout (<app-logout-button>) button.
That’s it folks! This is all you need to do to protect Routes in your Angular application with Auth0.
HTTP Interceptor to invoke the API backend
So far, we have been focusing on the user’s experience on the frontend. How to log them in, how to protect sensitive routes in our application depending on whether users are logged in.
What happens when we want to invoke an API backend? Feedback Pal uses an API backend written in Nest JS. Here’s the rub: on the frontend, we use Auth0 to authenticate users. Every time users log in, they receive an ID Token.
Try to access the Feedback Pal home page on http://localhost:4200 and then open the Developers Tools (Alt-Option + Command + I) on the Network tab.
If you Login and inspect the Network Tab, after a successful login, you will notice several token requests. These are the requests that the Auth0 Guard sends to Auth0 to retrieve a JWT and an ID Token. You can actually inspect the token content by copying the value of the access_token to https://jwt.io
This token contains all the information we have configured as part of our Auth0 setup.
If you keep scrolling to the right of the Response for the token request, you will find an id_token property, which you can also paste on https://jwt.io to inspect the content.
The ID Token
The ID Token looks very different from the access_token.
It doesn’t have the permissions section, which is fundamental for the API backend. The Feedback Pal frontend doesn’t really need permissions, so it uses the ID Token, rather than the acccess_token. However, when the frontend requires data and operations from the backend, it needs to pass the content of the access_token. How can we make this happen? The answer is to use the Auth0 HTTP Interceptor.
We have already mentioned this setup in the page explaining how to setup Auth0. Here we will delve a bit more into details.
From the ID Token to the JWT Token. Meet the Auth0 AuthHttpInterceptor
When configuring the Auth0 AuthModule, we pass in all the properties belonging to the auth object in the environment.ts file. We then configure the httpInterceptor property so that for every request issued to the list of allowed URLs, the interceptor will attached the JWT Token in the Authorization header before invoking the API backend.
In the providers section, we indicate that the HTTP interceptor to use is the Auth0 AuthHttpInterceptor. Now, every time a request is issued to the API backend which matches the allowedList, the interceptor will kick in and set the Authorization header with the following format:
Authorization Bearer <access_token>
In the API backend, of course, we will have something from the Auth0 SDK which extracts the JWT token and verifies the permissions, before allowing access to the resource. Look for the page explaining the API backend for more details on how this is achieved there.
With this setup in place, your Angular app is protected both from access to local frontend resources, as well as provides your API backend with the JWT token required to protect access to API resources.