angularasynchronousangular-auth-oidc-client

Error could not find matching config for state when using StsConfigHttpLoader


I am using angular-auth-oidc-client library v16.0.2 in angular project which is using v15.2.10. Everything works fine when I use static auth configs, but if I use async auth config, I get the error "could not find matching config for state ${stateParamFromUrl}" while authenticating the user.

auth-config.module.ts

/** Static config loading works perfectly fine */
export const StaticAuthConfigLoaderFactory = (): StsConfigLoader => {
            const authConfig = {
                    triggerAuthorizationResultEvent: true,
                    forbiddenRoute: `${window.location.origin}/error`,
                    unauthorizedRoute: `${window.location.origin}/error`,
                    logLevel: LogLevel.Debug,
                    historyCleanupOff: false,
                    authority: 'https://mySSO.com',
                    redirectUrl: `${window.location.origin}/callback`,
                    postLogoutRedirectUri: `${window.location.origin}/logout`,
                    clientId: 'angular-test',
                    scope: 'openid profile',
                    responseType: 'code',
                    silentRenew: false,
                    useRefreshToken: true,
               };
      return new StsConfigLoader(authConfig);
    }

/** Http config loading fails at callback */
export const HttpAuthConfigLoaderFactory = (httpClient: HttpClient): StsConfigLoader => {
  const authConfigPath = `assets/config/auth-config.json`;
  let authConfig$ = httpClient.get<OpenIdConfiguration>(authConfigPath)
    .pipe(
      catchError((err) => {
        console.error('Failed to load auth config', err);
        return throwError(err);
      }),
      map((customConfig: any) => {
        const obj = {
          authority: customConfig.authority,
          redirectUrl: customConfig.redirectUrl,
          clientId: customConfig.clientId,
          responseType: customConfig.responseType,
          scope: customConfig.scope,
          postLogoutRedirectUri: customConfig.postLogoutRedirectUri,
          silentRenew: false,
          postLoginRoute: customConfig.postLoginRoute,
          forbiddenRoute: customConfig.forbiddenRoute,
          unauthorizedRoute: customConfig.unauthorizedRoute,
          logLevel: LogLevel.Debug,
          historyCleanupOff: false,
        };
        return obj;
      })
    );
  return new StsConfigHttpLoader(authConfig$);
};
@NgModule({   imports: [
    AuthModule.forRoot({
      loader: {
        provide: StsConfigLoader,
        useFactory: HttpAuthConfigLoaderFactory,
        deps: [HttpClient],
      },
    }),   
   ],   
   exports: [AuthModule], 
}) 

export class AuthConfigModule { }

Solution

  • This may not be the correct answer, but I was able to solve the issue by saving the config (once fetched) in session cache and retrieving it later from the cache. Sequence and code snippets-

    Code Flow:

    1. Auth Config is fetched before the auth flow starts.
    2. CallBackComponent is called with the "code" from sso server.
    3. Once user is authenticated, user is auto redirected to the component which called Authorize() --> this is when no authGuards are used.
    4. Auth config is fetched again and this is when I was facing the error.

    Solution:

    1. Let dynamic auth config fetching be as is but save the config in session cache.

    2-3. No changes in these steps.

    1. Fetch the auth config from session cache and return StsConfigStaticLoader instead of StsConfigHttpLoader --> this fixed the issue for me.

    NOTE: I tried dynamic config with my SSO Server and clientID in sample-code-flow-http-config (https://www.npmjs.com/package/angular-auth-oidc-client), code flow is exactly the same as mine - Auth config is fetched twice, but I didnt see the issue I am facing --> Both the angular-auth-oidc-client lib & angular are on V18 with node v20.

    Code snippet:

    export const HttpAuthConfigLoaderFactory = (httpClient: HttpClient): StsConfigLoader => {
      const sessionCache = inject(SessionService);
    
      const cachedConfig = sessionCache.getItem('auth_config');
      **if (cachedConfig) {
        return new StsConfigStaticLoader(cachedConfig);
      }**
    
    const authConfigPath = `assets/config/auth-config.json`;
      let authConfig$ = httpClient.get<OpenIdConfiguration>(authConfigPath)
        .pipe(
          catchError((err) => {
            console.error('Failed to load auth config', err);
            return throwError(err);
          }),
          map((customConfig: any) => {
            const obj = {
              authority: customConfig.authority,
              redirectUrl: customConfig.redirectUrl,
              clientId: customConfig.clientId,
              responseType: customConfig.responseType,
              scope: customConfig.scope,
              postLogoutRedirectUri: customConfig.postLogoutRedirectUri,
              silentRenew: false,
              postLoginRoute: customConfig.postLoginRoute,
              forbiddenRoute: customConfig.forbiddenRoute,
              unauthorizedRoute: customConfig.unauthorizedRoute,
              logLevel: LogLevel.Debug,
              historyCleanupOff: false,
            };
            return obj;
          })
        );
      return new StsConfigHttpLoader(authConfig$);
    };
    

    For now the problem is solved for me. If I find any gaps in my code, I will update the thread.

    Thanks, RDV