Hi, is there any way to pass whitelistedDomains as a promise? The example bellow jwtOptionsFactory receives AppConfigService which returns the domain value. Just for the record, the service is provided as APP_INITIALIZER.
export function jwtOptionsFactory(appConfig: AppConfigService) {
return {
tokenGetter: TokenHelper.getToken,
headerName: 'token',
authScheme: '',
whitelistedDomains: [appConfig.domain],
blacklistedRoutes: []
};
}
I'd like to know whether this is possible as well.
This would be extremely helpful for use cases where the URL for the application's backend is dynamically configurable and needs to be retrieved from the application's assets, for example.
It's a bit ugly and hacky, the application might take slightly longer to load and the config can only be changed by reloading the application.
However, it works, so I'll post it anyway in case anyone runs into the same problem as I did.
EDIT:
See my next comment for instructions on how to make this work when building the application in prod mode (with AOT enabled).
I created a simple JS file inside assets which contains a function providing the endpoint config:
function getEndpointConfig() {
return {
"host": "localhost:3000",
"https": false
}
}
This JS file has to be included in src/index.html, inside the <head> tag:
<head>
...
<script type="text/javascript" src="assets/endpoint.js"></script>
</head>
Now you can fetch the backend host in your app.module.ts using your function defined in the script asset:
JwtModule.forRoot({
config: {
tokenGetter: tokenGetter,
whitelistedDomains: [window['getEndpointConfig']()['host']]
}
})
My workaround doesn't seem to work correctly when aot-compiling the application using ng build --prod.
So here's an even more hacky version of it:
Angular "precompiles" the output of all functions called inside module decorators - in this case, however, we need to actually get a value at runtime.
Angular also doesn't allow calling functions inside module decorators when building with AOT enabled.
However, it is possible to supply some sort of hardcoded value (for prod mode only) and replace it after the build has been completed:
JwtModule.forRoot({
config: {
tokenGetter: tokenGetter,
whitelistedDomains: [(environment.production ? '####BACKEND_HOST####' : getBackendHost())]
}
})
The function getBackendHost() should be defined in the same module file:
export function getBackendHost(): string {
return window['getEndpointConfig']()['host'];
}
Now you need to include a step in your buildscript that replaces "####BACKEND_HOST####" (note the double quotes in the js output) with window['getEndpointConfig']()['host'] in your main.*.js file after ng build --prod has completed.
My gulp task for replacing the backend host:
task('replaceEndpointHost', function(){
return src(['dist/my-app/main.*.js'])
.pipe(replace("\"####BACKEND_HOST####\"", "window['___getApplicationConfig___']()['endpoint']['host']"))
.pipe(dest('dist/my-app/'));
});
I am also interested in this feature
We'd welcome a PR to enable this feature, if it's something of interest.
Also interested in this feature
This feature is exactly what my app needs. My app is hosted on a node server that contains a relative endpoint, /configuration, which returns the location of our API, which lives on a different domain. This allows us to use a node environment variable on the node server to configure what API our app should make all its API calls to. As such, we don't know what domain to whitelist until our APP_INITIALIZER makes the call to /configuration. For this reason, we need this feature...we need whitelistedDomains to support Promises and/or Observables.
@shad1w what about using enviroment variable ?
+1, We need this feature as well.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you have not received a response for our team (apologies for the delay) and this is still a blocker, please reply with additional information or just a ping. Thank you for your contribution! 🙇♂️
ping
Any news on this feature?
I've found another workaround for this.
You can edit the JwtConfig provided by your factory in an APP_INITIALIZER before the JwtModule starts using it.
function jwtConfigFactory(jwtService: JwtService): JwtConfig {
return {
tokenGetter: () => jwtService.getToken(),
allowedDomains: [],
disallowedRoutes: [],
}
}
function jwtInitialiserFactory(configService: ConfigService, jwtConfig: JwtConfig): () => Promise<void> {
return async () => {
jwtConfig.allowedDomains.push(...(await configService.getPrivateDomains()));
jwtConfig.disallowedRoutes.push(...(await configService.getPublicUrls()));
};
}
const jwtOptionsProvider: Provider = {
provide: JWT_OPTIONS,
useFactory: jwtConfigFactory,
deps: [JwtService]
}
const jwtInitialiserProvider: Provider = {
provide: APP_INITIALIZER,
useFactory: jwtInitialiserFactory,
deps: [ConfigService, JWT_OPTIONS],
multi: true,
}
@NgModule({
declarations: [
AppComponent,
// ...
],
imports: [
// ...
JwtModule.forRoot({ jwtOptionsProvider }),
],
providers: [
// ...
jwtInitialiserProvider,
],
bootstrap: [AppComponent]
})
export class AppModule { }
Most helpful comment
This feature is exactly what my app needs. My app is hosted on a node server that contains a relative endpoint,
/configuration, which returns the location of our API, which lives on a different domain. This allows us to use a node environment variable on the node server to configure what API our app should make all its API calls to. As such, we don't know what domain to whitelist until ourAPP_INITIALIZERmakes the call to/configuration. For this reason, we need this feature...we needwhitelistedDomainsto support Promises and/or Observables.