Streamline Your Okta Configuration in Angular Apps

Streamline Your Okta Configuration in Angular Apps

The Okta Angular SDK supports a new and improved configuration method to pass in the required properties for incorporating Okta in your Angular applications. Now, you can add Okta to your Angular application using the forRoot pattern!

The forRoot pattern in Angular

The forRoot pattern helps ensure services defined in NgModules aren’t duplicated across the application. This is especially noteworthy if you have a module that both provides services and also has component and directive declarations. The intention for the forRoot static method is for importing and configuration to happen at the root module. This is good practice and recommended patterns for an authentication module! It can make configuring the NgModule more straightforward too!

Let’s take a look at an example case, such as a cupcake e-commerce application with a module containing a service and view for supporting denoting your favorite treats with a heart. 😋🧁💜

Your service code might look like this with the @Injectable() decorator:

@Injectable()
export class FavoriteCupcakeService {
    addCupcakeToFavorites(cupcake: Cupcake): Observable<Cupcake> {
        // make HTTP call to add a cupcake to favorite for this user
    }

    getFavoriteCupcakes(): Observable<Cupcake[]> {
        // make HTTP call to get all the favorite cupcakes for this user
    }
}

Additionally, you have a component that supports the favorite cupcakes feature in the favorite cupcake module:

@NgModule {
    declarations: [FavoriteCupcakeComponent],
    exports: [FavoriteCupcakeComponent],
    providers: [FavoriteCupcakeService]
}
export class FavoriteCupcakeModule {}

In your application module, you might import the FavoriteCupcakeModule, making the declared FavoriteCupcakeComponent and provided FavoriteCupcakeService available throughout your application.

But what if you don’t import the FavoriteCupcakeModule in the AppModule or if you want to use the FavoriteCupcakeComponent in a lazy-loaded feature module in your app? You’ll have to reimport the FavoriteCupcakeModule in that lazy-loaded module. Each lazy-loaded module has an injector instance, so you may have multiple instances of the FavoriteCupcakeService in your application, which we don’t want.

One option is to amend the @Injectable() decorator to add the metadata that determines where in the application the service is provided using the providedIn property:

@Injectable({
    providedIn: 'root'
})

This declaration within the decorator is preferable over providing the service within a module’s providers array because it supports tree-shaking.

Another option is adding the forRoot() static method to the FavoriteCupcakeModule and providing the FavoriteCupcakeServiceinstead of through the providers array. The FavoriteCupcakeService can and should be a singleton instance for the application, and the forRoot() static method sets the module up to do so.

Following in the steps of this best practice, the Okta Angular SDK now has more streamlined configuration options and helps promote good practices of importing the OktaAuthModule at the application root. Authentication applies to the entire application and should not depend on where you imported the OktaAuthModule in the application.

Let’s look at this configuration change.

Configuring the Okta Angular SDK using OAuth 2.0 and OpenID Connect (OIDC)

Previously, to incorporate Okta in your Angular applications, you had to import the OktaAuthModule and pass in your configuration in the providers array as a replacement for the OKTA_CONFIG injection token like this:

const oktaAuth = new OktaAuth({
    clientId: '{yourOktaClientId}',
    issuer: 'https://{yourOktaDomain}/oauth2/default'
});

@NgModule({
    imports: [ 
        OktaAuthModule 
    ],
    providers: [
        { provide: OKTA_CONFIG, useValue: {oktaAuth} }
    ]
})
export class AppModule { }

This method will continue to work, and you can continue using the module as you have it now without any changes.

However, you can now change your configuration to pass in your Okta config directly into the forRoot() method of the OktaAuthModule. Not only is this more straightforward, it sets your application up to practice better architecture:

const oktaAuth = new OktaAuth({
    clientId: '{yourOktaClientId}',
    issuer: 'https://{yourOktaDomain}/oauth2/default'
});

@NgModule({
    imports: [ 
        OktaAuthModule.forRoot({oktaAuth})
    ]
})
export class AppModule { }

The OktaAuthModule handles setting the OKTA_CONFIG injection token for you, so you won’t have to make that extra hop when adding Okta to your application! 🎉

Configuring Okta Angular application going forward

Since authentication-related services should be application-wide, we recommend using the OktaAuthModule.forRoot() static method when configuring Okta in new Angular applications. You’re still covered with backward-compatibility support if you have more complex needs, such as requiring a factory method to provide the OKTA_CONFIG injection token.

The Okta Angular SDK team plans to improve this in the future. They recognize the current OktaAuthModule can improve, and to truly support forRoot(), they will have to remove auth services from the providers array of the module, which breaks backward compatibility. The Okta Angular SDK team also is preparing to support the latest Angular features, which will become the Angular recommended patterns going forward, such as stand-alone components, module-less architecture, and functional route guards. If you have thoughts or input, or want to share how you use the Okta Angular SDK so the team can make sure they consider it, feel free to drop a note in the comment below.

Learn more about Angular, Dependency Injection, and OpenID Connect

If you liked this post, you might want to check out the following:

Remember to follow us on Twitter and subscribe to our YouTube channel for more exciting content. We also want to hear about what tutorials you want to see. Leave us a comment below.

Alisa Duncan is a Senior Developer Advocate at Okta, a full-stack developer, and a community builder who loves the thrill of learning new things. She is a Google Developer Expert in Angular and organizes coding workshops and community events locally and internationally. Her background is primarily working on enterprise software platforms, and she is a fan of all things TypeScript and JavaScript.

Okta Developer Blog Comment Policy

We welcome relevant and respectful comments. Off-topic comments may be removed.