Revert "Only use OIDC token when it's valid"

This reverts commit 63a5750f28.
This commit is contained in:
Amelia 2025-07-03 16:18:24 +02:00
parent 63a5750f28
commit 626bb3b719
5 changed files with 25 additions and 14 deletions

View file

@ -3,22 +3,20 @@ import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/c
import {Observable, switchMap} from 'rxjs';
import { AccountService } from '../_services/account.service';
import { take } from 'rxjs/operators';
import { OidcService } from '../_services/oidc.service';
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(private accountService: AccountService, private oidcService: OidcService) { }
constructor(private accountService: AccountService) {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return this.accountService.currentUser$.pipe(
take(1),
switchMap(user => {
if (user) {
const token = this.oidcService.hasValidToken() ? this.oidcService.token : user.token;
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
Authorization: `Bearer ${user.oidcToken ?? user.token}`
}
});
}

View file

@ -4,6 +4,9 @@ import {Preferences} from './preferences/preferences';
// This interface is only used for login and storing/retrieving JWT from local storage
export interface User {
username: string;
// This is set by the oidc service, will always take precedence over the Kavita generated token
// When set, the refresh logic for the Kavita token will not run
oidcToken: string;
token: string;
refreshToken: string;
roles: string[];

View file

@ -17,7 +17,6 @@ import {takeUntilDestroyed, toSignal} from "@angular/core/rxjs-interop";
import {Action} from "./action-factory.service";
import {LicenseService} from "./license.service";
import {LocalizationService} from "./localization.service";
import {OidcService} from "./oidc.service";
export enum Role {
Admin = 'Admin',
@ -47,7 +46,6 @@ export const allRoles = [
export class AccountService {
private readonly destroyRef = inject(DestroyRef);
private readonly oidcService = inject(OidcService);
private readonly licenseService = inject(LicenseService);
private readonly localizationService = inject(LocalizationService);
@ -94,6 +92,10 @@ export class AccountService {
});
}
oidcEnabled() {
return this.httpClient.get<boolean>(this.baseUrl + "oidc/enabled");
}
canInvokeAction(user: User, action: Action) {
const isAdmin = this.hasAdminRole(user);
const canDownload = this.hasDownloadRole(user);
@ -217,6 +219,7 @@ export class AccountService {
tap((response: User) => {
const user = response;
if (user) {
user.oidcToken = token;
this.setCurrentUser(user);
}
}),
@ -260,7 +263,7 @@ export class AccountService {
this.licenseService.hasValidLicense().subscribe();
}
// oidc handles refreshing itself
if (!this.oidcService.hasValidToken()) {
if (!this.currentUser.oidcToken) {
this.startRefreshTokenTimer();
}
}

View file

@ -11,7 +11,6 @@ import {DashboardUpdateEvent} from "../_models/events/dashboard-update-event";
import {SideNavUpdateEvent} from "../_models/events/sidenav-update-event";
import {SiteThemeUpdatedEvent} from "../_models/events/site-theme-updated-event";
import {ExternalMatchRateLimitErrorEvent} from "../_models/events/external-match-rate-limit-error-event";
import {OidcService} from "./oidc.service";
export enum EVENTS {
UpdateAvailable = 'UpdateAvailable',
@ -147,7 +146,7 @@ export class MessageHubService {
*/
public onlineUsers$ = this.onlineUsersSource.asObservable();
constructor(private oidcService: OidcService) {}
constructor() {}
/**
* Tests that an event is of the type passed
@ -166,7 +165,7 @@ export class MessageHubService {
createHubConnection(user: User) {
this.hubConnection = new HubConnectionBuilder()
.withUrl(this.hubUrl + 'messages', {
accessTokenFactory: () => this.oidcService.hasValidToken() ? this.oidcService.token : user.token
accessTokenFactory: () => user.oidcToken ?? user.token
})
.withAutomaticReconnect()
//.withStatefulReconnect() // Requires signalr@8.0

View file

@ -18,6 +18,7 @@ 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);
@ -55,6 +56,17 @@ export class OidcService {
});
}
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?
// TODO: Do we need to refresh the SignalR connection here?
user.oidcToken = this.token;
});
});
this.config().subscribe(oidcSetting => {
if (!oidcSetting.authority) {
this._loaded.set(true);
@ -109,8 +121,4 @@ export class OidcService {
return this.oauth2.getAccessToken();
}
hasValidToken() {
return this.oauth2.hasValidAccessToken();
}
}