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>

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