ERROR Error: Okta config is not provided at Object.create OktaAuth [as useFactory]

Hello Everyone,
i try to load Okta config and i get this error:
ERROR Error: Okta config is not provided
at Object.createOktaAuth [as useFactory] (okta-okta-angular.js:481:13)
at Object.factory (core.mjs:6263:38)
at core.mjs:6164:43
at runInInjectorProfilerContext (core.mjs:867:9)
at R3Injector.hydrate (core.mjs:6163:17)
at R3Injector.get (core.mjs:6033:33)
at injectInjectorOnly (core.mjs:911:40)
at ɵɵinject (core.mjs:917:42)
at Object.OktaAuthStateService_Factory [as factory] (okta-okta-angular.js:407:45)
at core.mjs:6164:43

Context:
@okta/okta-angular: 6.3.0
@okta/okta-auth-js: 7.4.3
Angular: 17.0.0
using standalone without NgModule.

app.component.ts

import { Component, Inject, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Router, RouterOutlet } from '@angular/router';
import {
  OKTA_AUTH,
  OKTA_CONFIG,
  OktaAuthModule,
  OktaAuthStateService,
} from '@okta/okta-angular';
import { OktaAuth, AuthState } from '@okta/okta-auth-js';
import config from './app.config';
import { Observable, filter, map } from 'rxjs';
const oktaConfig = new OktaAuth(config.oidc);

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet, OktaAuthModule],
  providers: [
    { provide: OKTA_AUTH, useValue: oktaConfig },
    { provide: OKTA_CONFIG, useValue: oktaConfig },
  ],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
  title = 'afx-afoms-frontend';
  public isAuthenticated$!: Observable<boolean>;
  constructor(
    private _router: Router,
    private _oktaStateService: OktaAuthStateService,
    @Inject(OKTA_AUTH) private _oktaAuth: OktaAuth
  ) {}
  public ngOnInit(): void {
    this.isAuthenticated$ = this._oktaStateService.authState$.pipe(
      filter((s: AuthState) => !!s),
      map((s: AuthState) => s.isAuthenticated ?? false)
    );
  }

  public async signIn(): Promise<void> {
    await this._oktaAuth.signInWithRedirect();
  }

  public async signOut(): Promise<void> {
    await this._oktaAuth.signOut();
  }
}

app.component.html

<div class="toolbar" role="banner">
  @if ((isAuthenticated$ | async) === false) {
  <button (click)="signIn()"> Sign in </button>
  }@else {
  <button (click)="signOut()">Sign out</button>
  }
</div>
1 Like

Hi there @GhostSY !

It’s on my list to get a tutorial/sample app together using standalone, but I don’t have one yet, so thank you for pointing out this need. :sweat_smile:

The OKTA_CONFIG provider doesn’t match what Okta Angular SDK expects, a property named oktaAuth. Can you try changing your provider OKTA_CONFIG to:

const oktaConfig = new OktaAuth(config.oidc);

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet, OktaAuthModule],
  providers: [
    { provide: OKTA_CONFIG, useValue: {oktaAuth: oktaConfig }},
  ],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})

Notice you won’t need to provide OktaAuth, only OKTA_CONFIG, but the object has a property named oktaAuth.

Alternatively, you can pass the configuration in directly when importing the module and not worry about overriding providers. I recommend this approach:

const oktaConfig = new OktaAuth(config.oidc);

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [
    CommonModule,
    RouterOutlet,
    OktaAuthModule.forRoot({ oktaAuth: oktaConfig })
  ],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})const oktaConfig = new OktaAuth(config.oidc);

Let us know if this works for you!

1 Like

I fixed the issue by add an app module then import it into the app component

import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { OktaAuthModule, OKTA_CONFIG } from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';
import myAppConfig from './app.config';
const oktaConfig = myAppConfig.oidc;
const oktaAuth = new OktaAuth(oktaConfig);
import { OktaAuthStateService } from '@okta/okta-angular';

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

I attempted to use the provided code, but unfortunately, it did not yield the desired results for me.
Thank you

Hey there @GhostSY ,

Glad to hear you got it working. I did a little digging and created a standalone application to verify. The issue you encountered is due to DI hierarchy.

Okta services are provided at root, so you’d have to override there, which you did by creating an app module. If you try importing the OktaAuthModule with providers configured, you’d see an error alerting this syntax is not supported at components.

I created a GitHub repo for a stand-alone Angular app utilizing Okta. I understand you resolved your issue, but I’m posting in case others encounter this as well. A blogpost is still forthcoming.

Happy coding!

Hello @alisaduncan,

I’m encountering another issue that I believe is related to the providers. When attempting to sign in using signInWithRedirect and redirecting to the login status in case of success, everything works perfectly. However, a problem arises when implementing a guard for a component called ‘dashboard’ to check if the user is authenticated. In this scenario, the user is not granted the ability to log in again because isAuthenticated is already true. Initially, an error occurs: [NullInjectorError: No provider for OktaAuthStateService], which I resolved by providing it in app.config.ts. However, a new error has surfaced: ERROR Error: NG0204: Can't resolve all parameters for OktaAuth: (?).

If you could assist me in resolving this error, I’d be happy to provide you with the relevant code.

app.config.ts

import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { environment } from '../environments/environment';
import {
  OktaAuthModule,
  OktaAuthStateService,
} from '@okta/okta-angular';
import OktaAuth from '@okta/okta-auth-js';
export const oidc = {
  clientId: environment.clientId,
  issuer: environment.issuer,
  redirectUri: environment.redirectUri,
  scopes: environment.scopes,
};

const oktaAuth = new OktaAuth(oidc);
export const appConfig: ApplicationConfig = {
  providers: [
    importProvidersFrom(OktaAuthModule.forRoot({ oktaAuth })),
    provideRouter(routes),
    OktaAuthStateService,
  ],
};

app.module.ts

import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { OktaAuthModule, OKTA_CONFIG, OKTA_AUTH } from '@okta/okta-angular';
import { OktaAuth } from '@okta/okta-auth-js';
import { oidc } from './app.config';
const oktaAuth = new OktaAuth(oidc);
import { OktaAuthStateService } from '@okta/okta-angular';

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

app.routes.ts

import { Routes, mapToCanActivate } from '@angular/router';
import {
  OktaCallbackComponent,
  OktaAuthGuard,
  OktaAuthStateService,
} from '@okta/okta-angular';
import { LoginComponent } from './modules/auth/components/login/login.component';
import { authGuard } from './core/guards/auth.guard';
import { DashboardComponent } from './modules/pages/dashboard/dashboard.component';
import { LoginStatusComponent } from './modules/auth/components/login-status/login-status.component';
import { OktaAuth } from '@okta/okta-auth-js';

export const routes: Routes = [
  {
    path: '',
    redirectTo: 'login',
    pathMatch: 'full',
  },
  {
    path: 'login',
    component: LoginComponent,
  },
  { path: 'login-status', component: LoginStatusComponent },
  { path: 'implicit/callback', component: OktaCallbackComponent },
  {
    path: 'dashboard',
    providers: [OktaAuthStateService, OktaAuth],
    canActivate: [authGuard],
    component: DashboardComponent,
  },
];

auth.guard.ts

import {
  ActivatedRouteSnapshot,
  CanActivateFn,
  Router,
  RouterStateSnapshot,
  UrlTree,
} from '@angular/router';
import { Inject, Injectable, inject } from '@angular/core';
import { OKTA_AUTH, OktaAuthStateService } from '@okta/okta-angular';
import { Observable, map, take } from 'rxjs';
import OktaAuth from '@okta/okta-auth-js';

export function authGuard() {
  const authStateService: OktaAuthStateService = inject(OktaAuthStateService);
  const router: Router = inject(Router);

  return authStateService.authState$.pipe(
    map((loggedIn) => {
      console.log('loggedIn', loggedIn);

      if (!loggedIn) {
        router.navigate(['/login']);
        return false;
      }
      return true;
    }),
    take(1)
  );
}

Hello @alisaduncan,

I wanted to let you know that I resolved my problem by importing the provider in the app.config.ts file. Your GitHub repository was immensely helpful. I opted to eliminate the app module and instead utilized the standalone component. I’m grateful for your assistance
thank you.

import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { environment } from '../environments/environment';
import { OktaAuthModule } from '@okta/okta-angular';
import OktaAuth from '@okta/okta-auth-js';
export const oidc = {
  clientId: environment.clientId,
  issuer: environment.issuer,
  redirectUri: environment.redirectUri,
  scopes: environment.scopes,
};

const oktaAuth = new OktaAuth(oidc);
export const appConfig: ApplicationConfig = {
  providers: [
    importProvidersFrom(OktaAuthModule.forRoot({ oktaAuth })),
    provideRouter(routes),
  ],
};

@GhostSY Glad to hear it!

Hello @alisaduncan,

I try to combine the 2 exemples of github, the standalone and the http config. When I set a breakpoint on the method of OktaAuthConfigService setConfig and getConfig and I call correctly setConfig but when okta call getConfig later, it is undefined.

app.config.ts

function configInitializer(httpBackend: HttpBackend, configService: OktaAuthConfigService): () => void {
  return () =>
  new HttpClient(httpBackend)
  .get('./assets/config.json') // this is from okta-angular-async-config-example repo's Express server
  .pipe(
    tap((authConfig: any) => configService.setConfig({oktaAuth: new OktaAuth({...authConfig.okta, redirectUri: `${window.location.origin}/login/callback`})})),
    take(1)
  );
}

export const appConfig: ApplicationConfig = {
  providers: [
    {
      provide: APP_INITIALIZER,
      deps: [HttpBackend, OktaAuthConfigService],
      multi: true,
      useFactory: configInitializer
    },
    provideRouter(routes),
    { provide: APP_BASE_HREF, useValue: '/' },
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
    provideHttpClient(
      withInterceptorsFromDi()
    ),
    importProvidersFrom(OktaAuthModule.forRoot()),
    provideAnimations(),
  ]
};

Can you add a third exemple to combine both.

Regards,
Julien Boulay

Hey there @JulienBy !

Yes! That’s the plan (to create an example utilizing both standalone and run time config loading). We need to fix a bug in the Okta Angular SDK for this all to work (it’s waiting for me to review and approve). I wonder if you’re seeing the same thing?

Once that happens, I’ll create the repo and get a blog post out. Stay tuned!

Hi,

Thank you for the answer. No I did not the this error. In my case, I use forRoot shoud’nt I?

I see the PR, do you have an estimate of the release date?

Julien

Hi there @JulienBy ,

Thanks for inquiring. Your request for this fix is noted. Unfortunately, I don’t have a date yet, but it is actively being worked on. I recommend subscribing to the PR so you get notifications.

Hi there @JulienBy !

The fix is merged and published in Okta Angular SDK 6.3.2. I will update the sample code repo to demonstrate using this in a standalone app soon.

1 Like

Hello @alisaduncan,
I’m having a similar issue when setting configurations through app_initializer (fetching config from api). setting config looks good, however getting config throws ‘Okta configis not provided’. I’m using the patched version of - Okta Angular SDK - 6.3.2. So was wondering if you have a tutorial available?

Hi @ellona_s!

I expect to have the written tutorial in the next month or so, but in the meantime, I updated my standalone example with a branch demonstrating HTTP config loading. You’ll update the src/api/config.json file for this example to run with your configuration info, but in reality your app will make an external HTTP call to an API for the config info. Depending on the API response, you may need to update the function provided to the APP_INITIALIZER.

Feel free to shout out if you have questions, and I’ll post in here when the tutorial is published!

1 Like

Thank you for your help! We managed to resolve the problem. Our application uses a complex modular architecture, and we faced an issue with multiple instances of OktaAuthService. This was due to the fact that OktaAuthModule was imported in both the main app module and a few others. This approach was a holdover from an older version of the Okta Angular SDK, where we loaded the Okta configuration in main.ts. However, with the updated SDK, we could load Okta configurations using APP_INITIALIZER. The challenge arose because we imported OktaAuthModule into several modules. While setting and retrieving configurations in the main module appeared to work fine, attempting to access Okta configurations in other modules resulted in ’ Okta config is not provided at Object.create OktaAuth [as useFactory]’ error.

Glad to hear you resolved the problem and appreciate you posting the resolution you found! Since OktaAuth should be provided at the root, what you saw and resolved makes total sense!

Good luck, and give us a shout if you run into any other problems!

1 Like

I have a slightly off-topic question. I’ve noticed that Okta stores transaction data in the local storage under the key ‘okta-shared-transaction’. I’m curious about how the Okta Angular SDK utilizes this data. When I attempted to shift this to session storage in my configurations, it still appeared in local storage, but as an empty item. Interestingly, everything continues to function correctly despite this. I’ve successfully moved ‘okta-tokens’ and ‘okta-cache’ to session storage, but I’m uncertain about how to handle this now-empty ‘okta-shared-transaction’. Could you guide me towards resources or information that might explain this behavior?

Hey there @ellona_s!

The okta-auth-js library handles the token storage (which Okta Angular SDK utilizes for ease of use within Angular apps).

You may have already done this, but here’s the config info for using local storage instead of session storage

Did you set the transaction configuration option as well? I haven’t done this before, so I’m not entirely sure it will resolve the empty transaction property from session storage, but worth a try. If you have follow-up questions or if setting the config option doesn’t resolve things, please create a new topic (feel free to tag me in it), and we can go from there with the next steps. :slight_smile:

Hello,
I am getting the same error Okta config not provided. I am using Angular 17 with a setup similar to the sample code: app.config.ts. The sample works, however I get the error above if I have a second APP_INITIALIZER attempting to set/load a second non-okta config file.

Snippet:

// config.json
export const configFactory = (configService: ConfigService) => {
  return () => configService.loadConfig();
};

// config-okta.json
// service that does the same as function configInitializer from sample
export const configOktaFactory = (configOktaService: ConfigOktaService) => {
  return () => configOktaService.loadConfig();
};

export const appConfig: ApplicationConfig = {
  providers: [
    importProvidersFrom(
      OktaAuthModule
    ),
    {
      provide: APP_INITIALIZER,
      multi: true,
      deps: [ConfigService],
      useFactory: configFactory
    },
    {
      provide: APP_INITIALIZER,
      multi: true,
      deps: [ConfigOktaService],
      useFactory: configOktaFactory,
    },
    ...

I have tried calling the configInitializer function directly in the second APP_INITIALIZER (same configuration as sample) but get the same result / error. So it’s not realted to my configOktaFactory. It all works if I take out the configFactory : APP_INITIALIZER.

I came across other issues trying to combine the two config files with additional properties not realted to OktaAuth. I may need to persist with a solution down this path as it would be cleaner then having two config files.

I have got around this by loading both config files in configService.loadConfig().