auth fixes

This commit is contained in:
2026-05-16 14:38:10 +00:00
parent 84038c25ec
commit 082e8d03ff
12 changed files with 224 additions and 56 deletions
+61 -3
View File
@@ -1,4 +1,5 @@
import type { Config, ConfigCreate, Project, ProjectCreate, ProjectUpdate, Repository, RepositoryConnection, RepositoryConnectionCreate, RepositoryCreate, Secret, SecretCreate, ToolDefinition, ToolInstance, User } from '../types/api.ts'
import { getToken, clearToken } from '../auth/oidc'
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'
@@ -13,8 +14,49 @@ export class ApiError extends Error {
}
}
function getAuthToken(): string | null {
return localStorage.getItem('access_token')
let isRefreshing = false
let refreshPromise: Promise<string | null> | null = null
async function refreshToken(): Promise<string | null> {
if (isRefreshing && refreshPromise) {
return refreshPromise
}
isRefreshing = true
refreshPromise = (async () => {
try {
const token = getToken()
if (!token) return null
const response = await fetch(`${API_URL}/api/v1/auth/refresh`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
})
if (!response.ok) {
clearToken()
return null
}
const data = await response.json()
if (data.access_token) {
localStorage.setItem('access_token', data.access_token)
return data.access_token
}
return null
} catch {
clearToken()
return null
} finally {
isRefreshing = false
refreshPromise = null
}
})()
return refreshPromise
}
async function fetchWithAuth(
@@ -22,7 +64,7 @@ async function fetchWithAuth(
options: RequestInit = {}
): Promise<Response> {
const url = `${API_URL}/api/v1${endpoint}`
const token = getAuthToken()
const token = getToken()
const headers: Record<string, string> = {
'Content-Type': 'application/json',
@@ -46,6 +88,22 @@ async function fetchWithAuth(
console.log(`[API] ${response.status} ${response.statusText}`)
}
if (response.status === 401 && token) {
const newToken = await refreshToken()
if (newToken) {
headers['Authorization'] = `Bearer ${newToken}`
const retryResponse = await fetch(url, {
...options,
headers,
})
if (!retryResponse.ok) {
const data = await retryResponse.json().catch(() => undefined)
throw new ApiError(retryResponse.status, retryResponse.statusText, data)
}
return retryResponse
}
}
if (!response.ok) {
const data = await response.json().catch(() => undefined)
throw new ApiError(response.status, response.statusText, data)