You can find many tutorials online about integrating OAuth2 / OIDC in your Angular app. Most of them tell you how to configure a lib like angular-oauth2-oidc or auth0.js inside an authorisation service, which redirects to the login-page upon the click of a “Login”-button. But what if you don’t want to display your app page for logged-out users at all? Every time the user visits your site, he is supposed to be greeted by the authorisation-server (e.g. the “login-page”) directly. This is a very common pattern when you develop some sort of a user-terminal application.

To see what I mean, check out the deployed final result of this tutorial:

https://philly-vanilly.github.io/init-auth

First the login-page, then the main page

Note: OIDC and OAuth2 are basically the same protocol, with the exception that with OIDC you also receive an id token containing user-information. I will refer to both protocols simply as OAuth2.

A naive integration approach would be to simply call your authorisation service inside the constructor of the app.component. But this way the user has to download the whole app.module with all its dependencies before the actual redirect.

Ideally, you would just load the authorisation code before app initialisation and make it either redirect to the login-page or (in case that the call is a redirect back from the login-page) to setup the auth-data provided inside the access token.

Now you could accomplish this “initial auth” in two ways:

Angular way: implementing APP_INITIALIZER and utilising lazy loading

VanillaJS way: validate the token inside index.html with a <script> tag

The VanillaJS approach can potentially make the initial load smaller, as Angular’s BrowserModule, RouterModule and HttpClientModule do not have to be loaded. However, those modules are only few hundred kb in size anyway and can be cached in the browser. Also, trying it out for angular-oauth2-oidc I realized the lib requires at least NgZone and HttpClient from Angular, so the size savings would probably be not as big as expected. More importantly, the vanilla approach requires bundling the auth lib from NPM yourself without the help of Angular CLI, making the app less maintainable. Writing your own token verification code (e.g. not using a lib) is also discouraged as this would be another case of reinventing the wheel.

So we will stick with the Angular approach. It does have one bigger downside though which is that you have to add an additional route fragment for the lazy loading. So you need to adjust all your routes accordingly; in a bigger app this might take time, but at least it is straightforward.

1. Make your main app.module lazily loaded

First thing you need to do is to introduce a new initial component that contains only a <router-outlet> …

… and a respective url-path-fragment for the lazily loaded module:

LazyModule in this example will be your old AppModule and the new AppModule will contain only this:

2. Implement APP_INITIALIZER

Now let’s take a look at the AuthModule imported by AppModule:

Here we provide an arrow function which implements APP_INITILIZER. This function gets executed by Angular on startup before any component is loaded. It always has to be provided inside the initial app.module. This is why we try to make app.module as tiny as possible; for example note how our AppComponent consists only of a router-outlet. In a real app the UI-modules and other heavy stuff would be placed in LazyModule.

Note: if you are not familiar with APP_INITILIZER, it allows you to run functions upon a module’s initialisation. You might be familiar with implementing a static forRoot (in an eager module) or forChild (in a lazy module) function like here. But these functions are only meant to return a ModuleWithProvider object from them in order to setup the module based on parameters. Any code that can’t be processed at compilation-time will throw an error in production when using AOT-compilation. To execute runtime code implement APP_INITILIZER instead.

Now let’s take a look at the implementation of the AuthService:

Note: In this case we are utilising the angular-oauth2-oidc lib, which works well with Auth-Servers like Keycloak or Identity-Server 4. For Auth0 or some other auth/id-provider you might consider using a different lib.

Upon an initial call of the app, we initialise the OAuth2 Implicit Flow (recommended for Single Page Applications like Angular), which means that we will be redirected to the external login page and be redirected back on successful login with all the data provided directly on the redirect (server-side rendered apps, e.g. PHP e.t.c. would make one more additional call). We prevent further loading of the app with a reject-callback.

After the redirect back to the app from the login-page, our auth-lib will recognise our logged-in status and this time call a success-callback, which will initialise the rest of the app. You might also want to decode the initial and refresh tokens here (every time there is an update-event), so when other parts of the app (e.g. guards) want to check the necessary permissions from the access-token or some components to display user-data from the id-token, they don’t have to decode them again.

You should also remove the redirect-hash (#state=xxxx) from the URL before the success-callback. Otherwise, if you are using the hash-fragment-scrolling, Angular router will throw an error on app-initialisation, freezing the app. The angular-oauth2-oidc lib removes the hash with a flag in the config; with other libs, you might need to do it manually by using Injector to get the router (see the commented out part of code).

That’s it!

Here is the full code of this deployed (see link at the top) prototype with additional comments and example-guards:

If you found the tutorial helpful, please 👏 one or more times ❤