I've got 2 APP_INITIALIZER providers... the first makes an HTTP request to get environment information.
The second uses the environment info to authorize the user against an OIDC Authority server endpoint (obtained from environment call).
It seems like, despite making the environment service a dependency of the authorization service, the authorization service's APP_INITIALIZER factory function is called before the environment call is completed.
{ provide: APP_INITIALIZER, multi: true, useFactory: EnvironmentFactory, deps: [] }
{ provide: APP_INITIALIZER, multi: true, useFactory: AuthorizationFactory, deps: [EnvironmentProvider] }
Both factories provided to APP_INITIALIZER are of the signature:
Factory() { return () => Promise; }
The result is that the authorization call submits to undefined
instead of a proper URL.
I've thought of combining the factories - but they are in two different modules so it feels messy. Guidance appreciated!
I ended up injecting the resolved EnvironmentProvider into the AuthorizationFactory.
I added an observable to the EnvironmentProvider that emits any time the Authority value changes.
{ provide: APP_INITIALIZER, multi: true,
useFactory: EnvironmentFactory, deps: [EnvironmentProvider] }
{ provide: APP_INITIALIZER, multi: true, useFactory: AuthorizationFactory,
deps: [AuthorizationProvider, EnvironmentProvider] }
export function AuthorizationFactory (auth: AuthorizationProvider, env: EnvironmentService) {
return new Promise((resolve, reject) => env.Authority$()
// don't emit until authority provider has a value
.skipWhile(authority => !authority)
// dispatch the auth command to ngrx/store.
.do(() => store.dispatch({ type: 'AuthorizeIdentity' }))
// switch to observe identity state
.switchMap(() => store.select('Identity'))
// don't emit until there is an identity (async authorization complete).
.skipWhile(identity => !identity)
// finish.
.take(1)
.subscribe(resolve, reject)
});
}
I use a ReplaySubject(1)
as the source for env.Authority$(). This ensures that the observable returned always emits upon subscription by the AuthorizationFactory (e.g. if the Authority was resolved prior to the AuthorizationFactory subscribing).
Anyone who comes across this wondering why I'm not using toPromise()... I think there is some issue (I've submitted for review here). https://github.com/Reactive-Extensions/RxJS/issues/1429
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With