Tweak refresh logic for OIDC
This commit is contained in:
parent
061fb222e6
commit
e5c716d234
2 changed files with 30 additions and 26 deletions
|
|
@ -4,13 +4,20 @@ import {from} from "rxjs";
|
|||
import {HttpClient} from "@angular/common/http";
|
||||
import {environment} from "../../environments/environment";
|
||||
import {OidcPublicConfig} from "../admin/_models/oidc-config";
|
||||
import {AccountService} from "./account.service";
|
||||
import {takeUntilDestroyed, toObservable} from "@angular/core/rxjs-interop";
|
||||
import {take} from "rxjs/operators";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
import {translate} from "@jsverse/transloco";
|
||||
import {APP_BASE_HREF} from "@angular/common";
|
||||
import {MessageHubService} from "./message-hub.service";
|
||||
|
||||
/**
|
||||
* Enum mirror of angular-oauth2-oidc events which are used in Kavita
|
||||
*/
|
||||
export enum OidcEvents {
|
||||
/**
|
||||
* Fired on token refresh, and when the first token is recieved
|
||||
*/
|
||||
TokenRefreshed = "token_refreshed"
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
|
@ -19,14 +26,14 @@ export class OidcService {
|
|||
|
||||
private readonly oauth2 = inject(OAuthService);
|
||||
private readonly httpClient = inject(HttpClient);
|
||||
private readonly accountService = inject(AccountService);
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly toastR = inject(ToastrService);
|
||||
private readonly messageHub = inject(MessageHubService);
|
||||
|
||||
protected readonly baseUrl = inject(APP_BASE_HREF);
|
||||
apiBaseUrl = environment.apiUrl;
|
||||
|
||||
public events$ = this.oauth2.events;
|
||||
|
||||
/**
|
||||
* True when the OIDC discovery document has been loaded, and login tried. Or no OIDC has been set up
|
||||
*/
|
||||
|
|
@ -47,29 +54,19 @@ export class OidcService {
|
|||
public readonly settings = this._settings.asReadonly();
|
||||
|
||||
constructor() {
|
||||
this.oauth2.setStorage(localStorage);
|
||||
|
||||
// log events in dev
|
||||
if (!environment.production) {
|
||||
this.oauth2.events.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(event => {
|
||||
if (event instanceof OAuthErrorEvent) {
|
||||
console.error('OAuthErrorEvent Object:', event);
|
||||
console.error('OAuthErrorEvent:', event);
|
||||
} else {
|
||||
console.debug('OAuthEvent Object:', event);
|
||||
console.debug('OAuthEvent:', event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.oauth2.events.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
|
||||
if (event.type !== "token_refreshed" && event.type != 'token_received') return;
|
||||
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
|
||||
if (!user) return; // Don't update tokens when we're not logged in. But what's going on?
|
||||
|
||||
user.oidcToken = this.token;
|
||||
this.messageHub.stopHubConnection();
|
||||
this.messageHub.createHubConnection(user);
|
||||
});
|
||||
});
|
||||
|
||||
this.getPublicOidcConfig().subscribe(oidcSetting => {
|
||||
this._settings.set(oidcSetting);
|
||||
|
||||
|
|
@ -96,6 +93,10 @@ export class OidcService {
|
|||
from(this.oauth2.loadDiscoveryDocumentAndTryLogin()).subscribe({
|
||||
next: _ => {
|
||||
this._loaded.set(true);
|
||||
|
||||
if (!this.oauth2.hasValidAccessToken() && this.oauth2.getRefreshToken()) {
|
||||
this.oauth2.refreshToken().catch(err => console.error("failed to refresh token on startup", err));
|
||||
}
|
||||
},
|
||||
error: error => {
|
||||
console.log(error);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import {TranslocoService} from "@jsverse/transloco";
|
|||
import {VersionService} from "./_services/version.service";
|
||||
import {LicenseService} from "./_services/license.service";
|
||||
import {LocalizationService} from "./_services/localization.service";
|
||||
import {OidcService} from "./_services/oidc.service";
|
||||
import {OidcEvents, OidcService} from "./_services/oidc.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
|
|
@ -52,7 +52,7 @@ export class AppComponent implements OnInit {
|
|||
private readonly document = inject(DOCUMENT);
|
||||
private readonly translocoService = inject(TranslocoService);
|
||||
private readonly versionService = inject(VersionService); // Needs to be injected to run background job
|
||||
private readonly oidcService = inject(OidcService); // Needed to auto login
|
||||
private readonly oidcService = inject(OidcService);
|
||||
private readonly licenseService = inject(LicenseService);
|
||||
private readonly localizationService = inject(LocalizationService);
|
||||
|
||||
|
|
@ -100,11 +100,15 @@ export class AppComponent implements OnInit {
|
|||
|
||||
this.localizationService.getLocales().subscribe(); // This will cache the localizations on startup
|
||||
|
||||
// Login automatically when a token is available
|
||||
effect(() => {
|
||||
const inUse = this.oidcService.inUse();
|
||||
// Update token, or login when one becomes available
|
||||
this.oidcService.events$.subscribe(event => {
|
||||
if (event.type !== OidcEvents.TokenRefreshed) return;
|
||||
|
||||
const user = this.accountService.currentUserSignal();
|
||||
if (!inUse || !this.oidcService.token || user) return;
|
||||
if (user) {
|
||||
user.oidcToken = this.oidcService.token;
|
||||
return;
|
||||
}
|
||||
|
||||
this.accountService.loginByToken(this.oidcService.token).subscribe({
|
||||
next: () => {
|
||||
|
|
@ -115,7 +119,6 @@ export class AppComponent implements OnInit {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@HostListener('window:resize', ['$event'])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue