Angular Authentication with Lazy Loading

Ravi Sevta
Cashify Engineering
4 min readJan 29, 2019
Angular Authentication

Cashify is an angular hosted application. Here we will discuss the complications with Auth Module and the way we handled them.

We had 3 major problems with Auth Module while optimizing ‘main chunk’ size:

1. Creating separate chunk and loading that chunk in memory.
2. Using Auth Module in CanActivate guard.
3. Handling the case where Auth Module loads after a module which is using AuthGuard.

Before proceeding, let me explain ‘AuthModule’ and ‘chunk’ — the two most used terms in this article.

AuthModule: A module in Cashify application which is used to handle user auth related functionalities like:
1. Login using the phone number, Google+ and Facebook accounts.
2. Logout from the app.
3. Manipulating auth data to check whether a user is logged in or not, getting auth token and more.

Chunk: It’s a piece of code that is bundled in a separate ‘.js’ file. If we don’t lazy load a module, then all compiled and build code of typescript goes to ‘main’ chunk.

How We Solved the Above Issues:

1. Creating Separate Chunk and Loading That Chunk in Memory

In Angular, we don’t have to do any extra work to create a chunk; RouterModule does that itself, if it finds ‘loadChildern’ in a router-config. For example:

Here in the above code, RouterModule creates a chunk of auth module, and as we navigate to ‘/auth’ module, it loads the created chunk in memory.

But for Cashify’s website, we have to load the auth module without navigating to a path. So, we write a service which loads created chunk in memory on demand.

We use NgModuleFactoryLoader to load the chunk and create a module from that chunk:

NgModuleFactoryLoader loads chunk by its name, a name which we have provided in RouterModule’s config as the loadChildren’s value. Below is a NgModuleFactoryLoader abstract class.

export declare abstract class NgModuleFactoryLoader {
abstract load(path: string): Promise<NgModuleFactory<any>>;
}

The ‘load’ method returns a promise of NgModuleFactory and with the help of ‘injector’, we create a module from that factory and get NgModuleRef in response.

export declare abstract class NgModuleFactory<T> {
abstract readonly moduleType: Type<T>;
abstract create(parentInjector: Injector | null):NgModuleRef<T>;
}

Take a look at the full code below:

In this step, we have completed the first milestone of creating chunk and loading that chunk in memory. Next, we have to use that module in Auth guard.

2. Using Auth Module in CanActivate guard

On Cashify’s website, we use AuthGuard to protect user data from direct navigation to auth required pages like Profile, Order, and Address.

Below is my previously implemented guard which uses AuthHelper to check whether a user is logged in or not. However, now AuthModule is lazy loaded, so we can’t use AuthHelper class directly.

To communicate with the lazily loaded module we need a publisher-subscriber model, and we have implemented that model by ‘rxjs/Subject’ in our Broadcast class.

So from AuthGuard, we have fired two events — ‘check_login’ and ‘request_login’ — first to check login and second for requesting login. Below is the code snippet for check_login:

return new Observable<boolean>(function (observe) {
BroadCast.instance.broadcast('check_login',(isLoggedIn) => {
if (isLoggedIn) {
observe.next(true);
observe.complete();
}else{
// TODO request for login
}
});
});

And to listen to these auth events we have implemented a service in the Auth module:

export class BroadcastEventService {
constructor(private authHelper: AuthHelper) {
BroadCast.instance.on('check_login',callback:()=>void)=>{
callback(this.authHelper.isUserLoggedIn());
});
// TODO handle request_login event here
}
}

3. Handling the Case Where Auth Module Loads After a Module Which is Using Auth Guard

All use cases are covered above except one, that is — what if AuthModule loads after a module(ProfileModule) which is using AuthGuard?

In that case, ‘check_login’ event fired by AuthGuard gets no response and page gets stuck in the middle of navigation.

This is a communication problem between guard and module. Actually, events are fired before auth service subscribes to these events. It is the case when we use Subject of ‘rxjs’ for a publisher-subscriber model; it does not hold previously fired event. So, to handle this case we use ReplaySubject which holds previously fired event and as Auth module loads, auth guard gets a response for these events.

--

--