About my blog

I write about the technical and non-technical aspects of software development

How it works

Microsoft ASP.NETASP.Net
BlogEngine.NET BlogEngine.NET
Azure DevOpsAzure DevOps

Contact info

 Email
 Contact

Follow me

Prod-20240407.1

Authenticating Angular with MSAL and NgRx

I continue my recent theme of securing applications with Microsoft Identity and OAuth2 in this article. This time I move on to the front-end, from which we need to interact with a secured Web API.

Authenticating Angular with MSAL and NgRx

I continue my recent theme of securing applications with Microsoft Identity and OAuth2 in this article. This time I move on to the front-end; specifically a Single-Page Application (SPA) with Angular, from which we will interact with a Web API secured with Microsoft Identity.

When building a SPA to a secured Web API there are two options. The first is to make the front-end responsible for authentication and authorisation, so it directly obtains a token that can be used to interact with our secured API.

The second is to delegate authentication to our Web API (assuming it is our API!); we add an endpoint on our custom API, which will conduct authentication and authorisation, then return a token to the front-end. This token can then be used on the secured endpoints of the API.

I might also add that if integrating with a 3rd party API, the choice may have already been made for us.

To delegate or not to delegate

For the first option, we need to ensure that our SPA has everything it needs to successfully authenticate. If we have roles (authorisation) to consider in the application, the logic needs to obtain this information from the token so that functionality may be customised.

For example a read-only user might have a more limited view or functionality compared to a read-write user.

With pure Microsoft Identity this is not a consideration (as roles are not supported), but when using Entra ID it generally is an important one.

If we choose authentication with delegation, we've already secured our API - so the configuration and mechanism is in place. However we still need to create an endpoint to handle the calls to authenticate, manage failed authentication and so on, which can add a bit more complexity to our Web API. The front-end however only needs to know this endpoint; it doesn't need to know anything about the authentication process, and can therefore be slightly simpler.

If you're using Microsoft Identity (as I am) then either approach will work well. If you're using Entra ID, I would lean towards the delegated method, leveraging the existing mechanism on the Web API. With Entra ID, we're almost certainly going to be using roles, and perhaps even AD Groups as a means to control access and functionality and although some aspects of this might manifest on the front-end (e.g. to show or hide some menu options, limit functionality) we would generally use these to control access to particular endpoints on the back-end thus preventing any chance of inappropriate access.

The demo application

Having said all the above, for my demo I've kept things relatively simple: I've implemented an SPA which will authenticate using Microsoft Identity. On successful authentication, the token will then be used to get profile data from Microsoft Graph, which is a surrogate for any other Microsoft Identity-protected API.

For an extra twist, I'm using NgRx state management to manage my user state, the state will contain my authentication details, and profile information.

I decided early on that I wanted a high degree of test coverage, so everything is wrapped with unit tests.

The code for this demo is on GitHub.

Download or clone the repository to a workstation. As prerequisites you'll need Node.js v22.15+, NPM v11.5.1+, and Angular CLI v20.1.3+. After navigating to the folder you've downloaded the application code into, run

npm install

to install all the app-specific dependencies.

Once dependencies are installed, you should be able to run the tests with

ng test

There should be 76 passing tests, exercising the fundamentals of the demo from the components, through state management, to the services.

Running the demo app

While unit tests give a degree of confidence that the application has been put together correctly and is logically sound, we need to run the demo in a browser to be sure!

So, we first we have to register our SPA callback URI on the Single-page application platform on an Azure App Registration. For this app, just running locally, the callback URI is http://localhost:4200.

App registration

We then need to update the environments.dev.ts with the Client ID, and Tenant ID from the App Registration. Since we're using Microsoft Identity, you can simply use the Microsoft Identity GUID of '9188040d-6c67-4c5b-b112-36a304b66dad'.


msalConfig: {
    clientId: 'ENTER_CLIENT_ID',
    tenantId: '9188040d-6c67-4c5b-b112-36a304b66dad',
},
usePopupAuthentication: false, // Set to true if you want to use popup authentication

Set the value of usePopupAuthentication to true if you want to enable popup dialogues for login and logout. If false, the app will redirect to login and logout pages. There doesn't appear to be any difference in outcome using either mechanism.

Now run

ng serve

On loading http://localhost:4200 we get the home page (unauthenticated).

Unauthenticated home page

Click the log in link or log in button on the navigation bar:

Log in with redirect setting

If you have enabled popup authentication in your environment.dev.ts, you should see

Login with popup setting

Enter your Microsoft login details. You may have additional stages of MFA (if configured on your account) and possibly a one-time dialog requesting permission for the app to access your user data.

Nevertheless, after successfully authenticating you should be redirected back the home screen, this time with your name:

Authenticated home page

Note the updated links on the navigation bar.

Click on the Profile button.  This will retrieve information from Microsoft Graph and store this in state management, thus avoiding repeat requests for the same data if we return to this page later. 

Profile screen

 

If you wish you can click the 'Home' icon on the navigation bar to return to the home page, but return to the profile page before continuing.

Let's test logout now. Make sure you're on the profile page. Click on the logout button:

Logout with redirect setting

If you have enabled popup authentication in your environment.dev.ts, the logout appears as a popup window as follows:

Logout with popup setting

 

Regardless of whether you've chosen redirect or popup, the app should eventually return to the home page.  This is because of a custom guard class AuthRedirectGuard:  when logout completes, the app attempts to return to the profile page. But the guard's CanActivate method will detect that the user is not authenticated, and direct the app on to a 'safe' page - in this case the home page.

That's all there is to it!

In a follow-up post I'll explain step by step on how to build this demo. Quite apart from the implementation of authentication, I found the process quite instructive in learning how to implement state management for this purpose and how to write unit tests to cover vital parts of this type of Angular application.

Don't forget you can get the code for this demo from GitHub if you want a head-start!  Happy coding!


You Might Also Like


Would you like to share your thoughts?

Your email address will not be published. Required fields are marked *

Comments are closed