Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

problem with allowedUrls and AOT #361

Closed
dragouf opened this issue Jun 19, 2018 · 11 comments
Closed

problem with allowedUrls and AOT #361

dragouf opened this issue Jun 19, 2018 · 11 comments

Comments

@dragouf
Copy link

dragouf commented Jun 19, 2018

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

@jeroenheijmans
Copy link
Collaborator

jeroenheijmans commented Jun 21, 2018

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...

@mjisaak
Copy link

mjisaak commented Sep 26, 2018

You made my day @jeroenheijmans 👌

@westerncj
Copy link

westerncj commented Oct 25, 2018

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,
    },
...

@jeroenheijmans
Copy link
Collaborator

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).

@Maximaximum
Copy link
Contributor

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?

@jeroenheijmans
Copy link
Collaborator

@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).

@Maximaximum
Copy link
Contributor

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.

@rutgervd
Copy link

rutgervd commented Dec 18, 2018

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?

@jbandi
Copy link

jbandi commented Mar 29, 2019

@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 ...

@jeroenheijmans
Copy link
Collaborator

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!

@dtiemstra
Copy link

dtiemstra commented Feb 17, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants