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 {HttpClient} from "@angular/common/http";
|
||||||
import {environment} from "../../environments/environment";
|
import {environment} from "../../environments/environment";
|
||||||
import {OidcPublicConfig} from "../admin/_models/oidc-config";
|
import {OidcPublicConfig} from "../admin/_models/oidc-config";
|
||||||
import {AccountService} from "./account.service";
|
|
||||||
import {takeUntilDestroyed, toObservable} from "@angular/core/rxjs-interop";
|
import {takeUntilDestroyed, toObservable} from "@angular/core/rxjs-interop";
|
||||||
import {take} from "rxjs/operators";
|
|
||||||
import {ToastrService} from "ngx-toastr";
|
import {ToastrService} from "ngx-toastr";
|
||||||
import {translate} from "@jsverse/transloco";
|
import {translate} from "@jsverse/transloco";
|
||||||
import {APP_BASE_HREF} from "@angular/common";
|
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({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
|
|
@ -19,14 +26,14 @@ export class OidcService {
|
||||||
|
|
||||||
private readonly oauth2 = inject(OAuthService);
|
private readonly oauth2 = inject(OAuthService);
|
||||||
private readonly httpClient = inject(HttpClient);
|
private readonly httpClient = inject(HttpClient);
|
||||||
private readonly accountService = inject(AccountService);
|
|
||||||
private readonly destroyRef = inject(DestroyRef);
|
private readonly destroyRef = inject(DestroyRef);
|
||||||
private readonly toastR = inject(ToastrService);
|
private readonly toastR = inject(ToastrService);
|
||||||
private readonly messageHub = inject(MessageHubService);
|
|
||||||
|
|
||||||
protected readonly baseUrl = inject(APP_BASE_HREF);
|
protected readonly baseUrl = inject(APP_BASE_HREF);
|
||||||
apiBaseUrl = environment.apiUrl;
|
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
|
* 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();
|
public readonly settings = this._settings.asReadonly();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
this.oauth2.setStorage(localStorage);
|
||||||
|
|
||||||
// log events in dev
|
// log events in dev
|
||||||
if (!environment.production) {
|
if (!environment.production) {
|
||||||
this.oauth2.events.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(event => {
|
this.oauth2.events.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(event => {
|
||||||
if (event instanceof OAuthErrorEvent) {
|
if (event instanceof OAuthErrorEvent) {
|
||||||
console.error('OAuthErrorEvent Object:', event);
|
console.error('OAuthErrorEvent:', event);
|
||||||
} else {
|
} 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.getPublicOidcConfig().subscribe(oidcSetting => {
|
||||||
this._settings.set(oidcSetting);
|
this._settings.set(oidcSetting);
|
||||||
|
|
||||||
|
|
@ -96,6 +93,10 @@ export class OidcService {
|
||||||
from(this.oauth2.loadDiscoveryDocumentAndTryLogin()).subscribe({
|
from(this.oauth2.loadDiscoveryDocumentAndTryLogin()).subscribe({
|
||||||
next: _ => {
|
next: _ => {
|
||||||
this._loaded.set(true);
|
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 => {
|
error: error => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import {TranslocoService} from "@jsverse/transloco";
|
||||||
import {VersionService} from "./_services/version.service";
|
import {VersionService} from "./_services/version.service";
|
||||||
import {LicenseService} from "./_services/license.service";
|
import {LicenseService} from "./_services/license.service";
|
||||||
import {LocalizationService} from "./_services/localization.service";
|
import {LocalizationService} from "./_services/localization.service";
|
||||||
import {OidcService} from "./_services/oidc.service";
|
import {OidcEvents, OidcService} from "./_services/oidc.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
|
|
@ -52,7 +52,7 @@ export class AppComponent implements OnInit {
|
||||||
private readonly document = inject(DOCUMENT);
|
private readonly document = inject(DOCUMENT);
|
||||||
private readonly translocoService = inject(TranslocoService);
|
private readonly translocoService = inject(TranslocoService);
|
||||||
private readonly versionService = inject(VersionService); // Needs to be injected to run background job
|
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 licenseService = inject(LicenseService);
|
||||||
private readonly localizationService = inject(LocalizationService);
|
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
|
this.localizationService.getLocales().subscribe(); // This will cache the localizations on startup
|
||||||
|
|
||||||
// Login automatically when a token is available
|
// Update token, or login when one becomes available
|
||||||
effect(() => {
|
this.oidcService.events$.subscribe(event => {
|
||||||
const inUse = this.oidcService.inUse();
|
if (event.type !== OidcEvents.TokenRefreshed) return;
|
||||||
|
|
||||||
const user = this.accountService.currentUserSignal();
|
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({
|
this.accountService.loginByToken(this.oidcService.token).subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
|
|
@ -115,7 +119,6 @@ export class AppComponent implements OnInit {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize', ['$event'])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue