Skip to content

Commit e232194

Browse files
fix(dashboard): redirect to oauth2-proxy on 401 instead of failing silently
When the kc-access cookie expires, k8s API calls return 401 and the SPA was left stuck on a stale page until the user manually cleared the cache. K8sClient now treats 401 as an auth boundary: a one-shot top-level navigation to /oauth2/start?rd=<current-url> (the oauth2-proxy re-auth convention). Overridable via K8sClientConfig.onUnauthorized; no-op outside the browser. A unauthorizedHandled latch prevents repeated redirects on concurrent 401s. Re-applied from cozystack/cozystack-ui#34 onto the in-tree console after the UI was vendored (#2963); the source repo is being archived. Related: #2788. A unit regression test is a follow-up — the k8s-client workspace package has no test harness yet. Co-authored-by: IvanHunters <[email protected]> Assisted-By: Claude <[email protected]> Signed-off-by: Myasnikov Daniil <[email protected]>
1 parent 1df8c7c commit e232194

1 file changed

Lines changed: 18 additions & 0 deletions

File tree

  • packages/system/dashboard/images/console/packages/k8s-client/src

‎packages/system/dashboard/images/console/packages/k8s-client/src/client.ts‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
export interface K8sClientConfig {
22
baseUrl?: string
33
getToken?: () => Promise<string>
4+
onUnauthorized?: () => void
5+
}
6+
7+
function defaultOnUnauthorized(): void {
8+
if (typeof window === "undefined") return
9+
const rd = window.location.pathname + window.location.search + window.location.hash
10+
window.location.assign(`/oauth2/start?rd=${encodeURIComponent(rd)}`)
411
}
512

613
export class K8sApiError extends Error {
@@ -24,10 +31,19 @@ export class K8sApiError extends Error {
2431
export class K8sClient {
2532
private baseUrl: string
2633
private getToken?: () => Promise<string>
34+
private onUnauthorized: () => void
35+
private unauthorizedHandled = false
2736

2837
constructor(config: K8sClientConfig = {}) {
2938
this.baseUrl = config.baseUrl ?? ""
3039
this.getToken = config.getToken
40+
this.onUnauthorized = config.onUnauthorized ?? defaultOnUnauthorized
41+
}
42+
43+
private handleUnauthorized(): void {
44+
if (this.unauthorizedHandled) return
45+
this.unauthorizedHandled = true
46+
this.onUnauthorized()
3147
}
3248

3349
private async request<T>(path: string, init?: RequestInit): Promise<T> {
@@ -63,6 +79,7 @@ export class K8sClient {
6379
} catch {
6480
body = `Server returned ${res.status} ${res.statusText}`
6581
}
82+
if (res.status === 401) this.handleUnauthorized()
6683
throw new K8sApiError(res.status, body)
6784
}
6885

@@ -256,6 +273,7 @@ export class K8sClient {
256273
})
257274

258275
if (!res.ok) {
276+
if (res.status === 401) this.handleUnauthorized()
259277
throw new K8sApiError(
260278
res.status,
261279
await res.json().catch(() => res.statusText),

0 commit comments

Comments
 (0)