Angular-oauth2-oidc: problem with allowedUrls and AOT

Created on 20 Jun 2018  路  11Comments  路  Source: manfredsteyer/angular-oauth2-oidc

I have a problem with allowedUrls in :

OAuthModule.forRoot({
            resourceServer: {
                allowedUrls: [varFromConf],
                sendAccessToken: true
            }
        })

I want to pass a variable to it because it come from configuration stuff but when it's compile by AOT my variable is replaced by null and so authorization token is not sent later.

Is there any workaround for this problem ? I dont want to hard code here my allowed urls...

for the moment what I did is to iOAuthModuleConfig from may main app.component and then set resoureServer from there.

constructor(private moduleConfig: OAuthModuleConfig) {
  this.moduleConfig.resourceServer.allowedUrls = [(<any>window).ServerConfig.ApiBaseUrl];
}

But I don't know if it's a good thing

Most helpful comment

I suggest doing this in app.module.ts:

import { OAuthModuleConfig, OAuthModule } from 'angular-oauth2-oidc';
import { authConfigFactory } from './auth-config-factory';

//...
    imports: [
      OAuthModule.forRoot(),
      // ...
    ],
    providers: [
      { provide: OAuthModuleConfig , useFactory: authConfigFactory, deps: [ConfigService] },
      // ...
    ]

// ...

and then this in auth-config-factory.ts:

// imports here

export function authConfigFactory(service: ConfigService): OAuthModuleConfig {
  return {
    resourceServer: {
      allowedUrls: [service.getVarFromConf()],
      sendAccessToken: true,
    }
  };
}

or something similar...

All 11 comments

I suggest doing this in app.module.ts:

import { OAuthModuleConfig, OAuthModule } from 'angular-oauth2-oidc';
import { authConfigFactory } from './auth-config-factory';

//...
    imports: [
      OAuthModule.forRoot(),
      // ...
    ],
    providers: [
      { provide: OAuthModuleConfig , useFactory: authConfigFactory, deps: [ConfigService] },
      // ...
    ]

// ...

and then this in auth-config-factory.ts:

// imports here

export function authConfigFactory(service: ConfigService): OAuthModuleConfig {
  return {
    resourceServer: {
      allowedUrls: [service.getVarFromConf()],
      sendAccessToken: true,
    }
  };
}

or something similar...

You made my day @jeroenheijmans 馃憣

I'm having a similar issue. I'm using APP_INITIALIZER to load my config settings from a json file, but for some reason it's calling the authConfigFactory before APP_INITIALIZER has finished. It gives me an undefined error for allowedUrls (I get allowedUrls from the config file).

Here's what my app.module.ts looks like. Is there a way to wait until APP_INITALIZER is finished before calling the authConfigFactory or another way I can set the allowedUrls based off a config file?

 providers: [
    AppConfigService,
    {
      provide: APP_INITIALIZER,
      useFactory: (config: AppConfigService) => () => config.load(),
      multi: true,
      deps: [AppConfigService]
    },
    {
      provide: OAuthModuleConfig,
      useFactory: authConfigFactory,
    },
...

You might have a related but different issue @westerncj. I'm unable to tell based on shown code alone though.

Most likely your scenario is not really an _issue_ with the library, but a question about how to structure/order things in your app. Perhaps a Stack Overflow question would be a better fit? Otherwise opening a new issue could possibly work. But in either case it might be good to have a little more code (a StackBlitz example would be nice).

I'm having the same issue as the Original Poster. Does it have anything to do with the library or is it just an Angular problem?
Is there a simpler, more 'official' way to make it work, rather than the one suggested by @jeroenheijmans?

@Maximaximum What is the 'problem' that's left over? If your OAuthModuleConfig has a dependency on dynamic data, then Angular DI and a Service seem like the idiomatic solution?

Either way, I'm pretty confident that there's no other way (though happy to learn one of course!). Perhaps the only thing to simplify this approach is to import environment stuff directly to be part of a constant config (but OP suggested needing something more dynamic).

Ok, I just figured out that I was using a dynamic value whereas I should use a static one. I've fixed my problem, so sorry for bothering.

I'm having the same ordering issue as @westerncj above. The OAuthConfig is setting the allowedUrl before the call to get the dynamic variables is finished. The relevant code bits:

const appInitializerFn = (appConfig: ConfigService) => {
  return () => {
    return appConfig.loadAppConfig();
  };
};

providers: [
  { 
    provide: APP_INITIALIZER, 
    useFactory: appInitializerFn, 
    multi: true, 
    deps: [ConfigService] 
  },
  { 
    provide: OAuthModuleConfig, 
    useFactory: authConfigFactory, 
    deps: [ConfigService] 
  }
]

export function authConfigFactory(service: ConfigService): OAuthModuleConfig {
  return {
    resourceServer: {
      allowedUrls: [service.environment.base_url],
      sendAccessToken: true,
    }
  };
}

loadAppConfig() {
    const http = this.injector.get(HttpClient);
    return http.get('/assets/settings/environment.json')
      .toPromise()
      .then(data => {
        this.environment = Object.assign({}, this.environment, data);
      });
}

How can I force the authConfigFactory to wait to run until after the loadAppConfig async call is finished?

@westerncj @rutgervd
I was able to solve the timing dependency between OAuthModuleConfig and APP_INITIALIZER in a client project. Unfortunately I do not have the exact code available any more, but the solution was the follwing:

The factory for the OAuthModuleConfig initialized the resourceServer with an empty array for allowedUrls:

export function authConfigFactory(service: ConfigService): OAuthModuleConfig {
  return {
    resourceServer: {
      allowedUrls: [],
      sendAccessToken: true,
    }
  };
}

The APP_INITIALIZER then gets the OAuthModuleConfig injected and after loading the config from the server it sets the allowedUrls on the resourceServer:

{ 
    provide: APP_INITIALIZER, 
    useFactory: appInitializerFn, 
    multi: true, 
    deps: [ConfigService, OAuthModuleConfig ] 
  },
loadAppConfig(config: ConfigService, oAuthConfig: OAuthModuleConfig ) {
    const http = this.injector.get(HttpClient);
    return http.get('/assets/settings/environment.json')
      .toPromise()
      .then(env=> {
        config.data = env.data;
        oAuthConfig.resourceServer.allowedUrls = env.allowedUrls;
      });
}

This seemed to work ...

Original question seems to have several good solutions and workarounds from follow-up comments. Let us know if there's still an open issue and we could reopen and investigate further!

I faced the same problem and found a different solution.
The problem with initializing your setting using APP_INITIALIZER is that loading the configuration is mostly async (using a promise) and the factory methods in your module are called before this promise is resolved.

You can however load the settings BEFORE bootstrapping the Module. Inside your App.module/other components you can access your settings without having to fear the settings are not loaded. I have created an example of how to accomplish this: github.com/dtiemstra/AngularConfigDemo

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Swissbite picture Swissbite  路  4Comments

uzzafar picture uzzafar  路  4Comments

uzzafar picture uzzafar  路  4Comments

medokin picture medokin  路  4Comments

jeroenheijmans picture jeroenheijmans  路  4Comments