Securing your Angular 7+ application with OIDC and NgRx

𝐀𝐥𝐞𝐱
5 min readNov 5, 2018

--

NG OIDC Client is an Angular Module combining OpenID Connect / OAuth2 using oidc-client with NgRx.

We’ll be building a basic Angular application with the help of the ng-oidc-client library and an IdentityProvider of your choice to enable a user to authenticate either through a popup or redirect.

At the end, through a series of posts we will be looking into how to protect our routes and use a bearer token to access API endpoints. We’ll explore several new ways to take advantage of having authentication part of your application state using NgRx by using actions and effects.

If you want to skip the talk and start right away, head over to GitHub and look at the final code we’re going to create over the course of this and upcoming posts: https://github.com/alx-andru/draft

Setting things up 🤖

Let’s build our very minimalistic App from the ground up and dive into some of the topics. To keep things simple we’ll put zero effort in styling but remain focused on showing how things work. If you’d like to see a prettier and more functional variation, have a look at the official GitHub Repo for ng-oidc-client.

Requirements: You’ll need node.js and npm (or yarn) installed on your system

If you haven’t yet, install Angular CLI (7.0.3) using npm

npm i -g @angular/cli

Create a new Angular project with your app name, here we simply call it DraftApp.

ng new DraftApp

Install the main package ng-oidc-client

npm i -s ng-oidc-client 

and it’s peer dependencies:

npm i -s oidc-client
npm i -s @ngrx/store @ngrx/effects

Now we can add the three modules StoreModule, EffectsModule and NgOidcClientModule to the AppModule in our application.

NgOidcClientModule is adding its own slice of state of NgRx following the Feature Module State Composition which is why we have to initialize StoreModule and EffectsModule with an empty forRoot.

Let’s look closer at the configuration of the NgOidcClientModule.

oidc_config: {
client_id: '...',
response_type: '...',
scope: '...',
authority: '...',
redirect_uri: '...',
post_logout_redirect_uri: '...',
silent_redirect_uri: '...',
automaticSilentRenew: true // optional
}

The ng-oidc-client library is a wrapper around oidc-client to use it in angular through services and facades in combination with state management, which is why the entire oidc-config is actually the oidc-client configuration passed through, to be used by oidc-client itself.

We also enabled the automaticSilentRenew to ensure that our token, once obtained is automatically being renewed.

To continue, you need a working Identity Provider, here are some options: (Each of the platforms provides great documentation on their respective websites on how to create a new application, set the right CORS policies, redirect and logout urls.

IdentityServer4 https://identityserver.io/

To continue right away with our example, we’ve already created an Identity Provider using IdentityServer4 for you to test and play around with.
You’ll find the all the resources for it on GitHub if you’d like to create one on your own: https://github.com/Fileless/ng-oidc-client-server

This implementation is solely for the purpose of testing and should not be used in production!

If you just want to learn how ng-oidc-client works, feel free to continue without any further changes of the configuration.

Auth0https://auth0.com/

Replace YOUR_DOMAIN in the following listing with your Auth0 domain account and YOUR_CLIENT_ID with the client id.

example configuration using auth0 as an Identity Provider

Unfortunately Auth0 is not compliant to the OpenID Connect specification for the end_session_endpoint which makes it necessary to configure a custom url endpoint in the format

https://YOUR_DOMAIN.auth0.com/v2/logout?returnTo=YOUR_CALLBACK_URL_ENCODED

To help oidc-client to resolve the rest of the required urls, you have to manually set the issuer, authorization_endpoint and userinfo_endpoint within the metadata attribute as well.

Oktahttps://okta.com

Replace YOUR_DOMAIN in the following listing with your Okta domain account and YOUR_CLIENT_ID with the client id.

Azure Active Directoryhttps://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app

Replace TENANT_ID and CLIENT_ID in the following listing with your information.

Unfortunately Microsoft has their own implementation on top of OpenID Connect to allow multi-tenancy. In addition CORS prevents the automated discovery of the necessary configuration through the .well-known/openid-configuration endpoint. Therefore you have to provide this information manually through the metadata and the signinKeys. You can discover the array of keys through following link:

https://login.microsoftonline.com/TENANT_ID/discovery/v2.0/keys

What Identity Providers are you using? If you’d like to see more examples or even an entire post, leave a comment!

As the Identity Provider will redirect back to our site to pass over the authenticated user, we have to set up a few static pages. In this example we keep the authentication, silent renew and sign-out callbacks separate from each other.

We’ll be placing our *callback.html files in a directory called src/static

DraftApp/
...
src/static
├── callback.html
├── renew-callback.html
└── signout-callback.html
...

The following example html files are opinionated and are intended to be flexible using ng-oidc-client. The minimum requirement is to import oidc-client.min.js and invoke the appropriate callback on the UserManager e.g. invoke signinRedirectCallback() to complete the signin via redirect.

new Oidc.UserManager().signinRedirectCallback().then(function(usr) {
log("signin response success", user);
}).catch(function(err) {log(err);});

To be able to serve our src/static files and oidc-client, we need to modify the angular.json configuration for our app to include those assets.

Now the base configuration is done and we can start to implement the authentication flow in our user interface.

The First Login 🥇

To get started we’ll add a simple login button to authenticate with a redirect in the same window and display the authenticated user information as seen below:

To keep things simple we modify our already existing app.component.ts to include the login and load the identity.

If you look at the imports, We’re using the OidcFacade from ng-oidc-client but resolving the identity as a User from oidc-client which is directly accessible as an Observable via the facade.

To get the user as soon as the app is loaded, we call getOidcUser(). This will cause oidc-client to look for a stored user identity. (By default oidc-client uses the Session Storage).

To sign-in and -out we simply invoke the functions on the OidcFacade.

Before we can test everything we still need to add the buttons and the identity in our app.component.html.

You should be able to sign-in as the user bob (or alice) with the password bob (or alice) if you used the provided IdentityServer4 example.

Now that we have the foundation of our application we can start exploring the capabilities of the library through these follow up posts:

Feel free to leave comments with any questions, feedback or ideas 🙌 …

--

--

𝐀𝐥𝐞𝐱

VP, Engineering at sherpa° — helping travellers around the world navigate complex travel restrictions — bringing visas as ancillary services to airlines