Token Based Security: Angular Applications

Introduction

I have written few posts on token based security, its importance, OAUTH, OIDC and IdentityServer. You can check previous post if you are new to these topics.

Today, I will write about how to secure angular application with these technologies. We will see how to wire Angular application with IdentityServer.

Angular application is a public client type of application, these applications are not capable of keeping a secret like server-side client applications e.g. ASP .NET MVC, Nodejs etc.

In the past Implicit flow was used for angular but its no longer recommended. As we learned in previous posts that AuthorizationCode + PKCE is the norm today.

This flow involves redirection to IdentityServer from an angular app and there user enters Login/Password on IDP, validated there and then redirected back to angular application.

I have seen many applications with in-app login screens (e.g. inside an Angular application), though this can be done (usually using Resource-Owner Password Flow), but if possible, avoid this practice. It creates more issues than it solves. If you are not happy with IDP default views for login/logout, you can rather style/change IDP screens instead of building login/logout etc. screens inside your angular application.

In this post, we will cover the recommended flow, but, first, we need some API endpoint (on resource server) that will return some data. Let’s create a simple endpoint next:

API Endpoint

I have an API, which is just a .NET Core web application. To start with, I created an API for Products as shown below, which uses dapper and postgreSQL to read data from database and return it to the caller in JSON format:

(I am using postgres db with dapper ORM, you can actually just return in-memory data and skip db part totally, if you like).

Next, we will create an angular application and a Products component. Angular application, will make HTTP call to the Get endpoint on ProductsController and receive the JSON data which it will then display using HTML.

Angular Application

I have created a very basic angular application using angular-cli. Application contains a product component which displays products data in a table. You can use your own existing or new angular application and the mechanism will be the same.

This is also a service api.service.ts which makes HTTP calls to backend API endpoint (ProductsController):

Now, if we run the angular app and visit the products page, the product is displayed on the page:

So, our angular application is able to call the API endpoint and get the data. Next, let’s protect this API endpoint:

Protecting the API

Let,s protect the API by applying Authorize attribute:

Restart the web applications and try to open up the product page again and no data will be shown, open up the console window and we have a 401 error shown:

So, the API is protected and only authorized clients can access it.

Now, at this point, we have a Products API endpoint in resource-server which is protected using Authorize attribute. Our IdentityServer is protecting the resource server. We also have an Angular application, which make an HTTP call to Products API endpoint. Next, let’s make necessary steps to make this HTTP call authorize to get data.

OIDC Client

To wire-up our angular application to authorization server and to deal with various flows, we can use oidc client library to manage this redirection and protocol level details for us.

You can install the package using npm command:

npm install oidc-client

Next, we will create a service (AuthService) which will act as a security context for our angular application. This service will internally use oidc library as needed.

Auth Service

We will start by creating this service. Auth service will use oidc library and will do the hard work of authenticating with oidc for us.

first, we will imported UserManager and User type from oidc library. These are the primary types you you’ll deal with from oidc client.

Next, we included private fields for UserManger and User type. UserManager will produce User at completion of login process. Next, we initialized UserManager in the constructor of AuthService.

We will see user variable shortly.

  • UserManager object manages all the low level protocol details of OIDC flows for us. So, we don’t have worry about what’s going-on at a wire level between our app and identity provider.
  • User type encapsulates the client-side info about a signed-in user, such as
    • ID and Access Tokens returned from IDP
    • Any user Profile information returned from IDP as Claims.
    • and being able to when the tokens for the user are expired.

In the constructor of service, we are initializing UserManager with stsSettings. If you remember from our Postman demos, you may recognize few of those already.

  • redirect_uri: This is the uri when IdentityServer redirect back after login process. We will create an angular component for this.
  • post_logout_redirect_uri: Similar to above, we will create an angular component to deal with when user logout on STS and redirected back to angular application.

These two components will be very simple, mostly with only one empty div and some JavaScript. We will see these two components later in the post.

Login Process

Next, I added a login method in AuthService, which call singinRedirect on userManager object:

after successful login, UserManager stores in session storage the resulting user object that it creates, so that it can be retrieved anytime it is needed, such as to get the AccessToken to send it to the API calls.

User object contains the Access and ID Tokens, as well as an expired flag which we can check to make sure that access token is not expired.

isLoggedIn Helper Method

In the code picture above, I created isLoggedIn method. This method will help us find out from any component that “check if user is already logged in“.

Raising Event When User is Loaded

When the redirect comeback into angular app from the STS, the process that obtains the ID and ACCESS TOKENS happens asynchronously from the loading of the root view. So, we’ll also need to raise an event when the user is loaded (see image below), so UI that depends on that can be updated. We’ll use an RxJs observable to do that:

So, to achieve this, we will declare a private property _loginChangedSubject on AuthService that is an RxJs subject and then a public observable _loginChanged that is produced by the subject. We then add code to fire that observable in the isLoggedIn method.

We’ll also fire this observable when the login process completes, but we will come back to that part a little bit later.

Loading User from Session Storage

Next, update root AppComponent with IsLoggedIn check so the user gets loaded on launch if there’s already one in the session storage from a previous login.

I’ also added an event handler to update isLoggedIn property when the logged in status changes.

So, the app component will be now notified whenever user status changes and application will be able to react to that change.

Login/Logout Buttons and Method

Next, I added Login/Logout Buttons (HTML) and method in AppComponent:

and here is the login/logout methods code:

We still have to setup login and singout callback components and some more angular code. We also need to configure STS with angular client settings. However, to keep post length in control, we will pause now and will continue in next post for the remaining setup. You can download the source code from this git repository. We will continue this setup in next post, if you have some comments or questions, let me know. Till next time, Happy Coding.

My Recent Books

1 thought on “Token Based Security: Angular Applications”

Comments are closed.