I'm using angular-oauth2-oidc for authentication. It's configured to use a 3rd partry SSO identity provider. The setup of my app follows https://github.com/jeroenheijmans/sample-angular-oauth2-oidc-with-auth-guards. The IdP doesn't implement Session Status Change Notifications, but I need to know if the user logs out or changes while navigating back and forth between my site and the IdP. So I'd like repeat the authentication request with prompt=none every time the page loads, even if there is a non-expired access token in sessionStorage. I tried changing runInitialLoginSequence
and executing oauthService.silentRefresh()
before checking oauthService.hasValidAccessToken()
but that leads to an endless loop.
So my question is what is the correct way to trigger an authentication request with prompt=none every time my page loads in this setup?
**Scenario 1: "page load" means "SPA load"
I reckon that if you change the runInitialLoginSequence
to merely remove the hasValidAccesstoken
check then that should do the trick. Then the silentRefresh
runs each time the APP_INITIALIZER runs (so every time your SPA is freshly loaded).
The canActivateProtectedRoutes$
observable will not emit any value until both isDoneLoading$
(the login sequence being done) emits, and the isAuthenticated$
emits (which by default it always does, as it's a BehaviorSubject
with a default of `false).
The guards will wait until isDoneLoading$
emits, which won't happen until the silentRefresh
has completed.
Scenario 2: "page load" also means "Angular Route Change"
So if you also want the silent refresh to do a check each time the route changes, you'll have to do extra modifications.
In this case you'll need to modify the guards and/or use Angular's Router events to trigger the silent refresh, and make sure everyone waits until it has completed.
A straightforward (though perhaps not optimal or pretty) way to do it would be to change the AuthGuard
(the one without forced login) to something like this:
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
): Observable<boolean> {
return this.authService.waitForNewSilentRefreshCallToBeCompleted$ // << Changed
.pipe(map(_ => this.authService.canActivateProtectedRoutes$) // << Changed
.pipe(tap(x => console.log('You tried to go to ' + state.url + ' and this guard said ' + x)));
}
Note that the // << Changed
lines are pseudo-code, you'll have to implement something like that on the service yourself. It's not already in the sample.