fix(auth): Resolve lint regressions and add security regression test

This commit is contained in:
Yunxiao Xu
2026-02-18 14:56:17 -08:00
parent f5aeb9d956
commit cc927e2a90
2 changed files with 19 additions and 5 deletions

View File

@@ -60,3 +60,17 @@ def test_refresh_token_wrong_type(client):
response = client.post("/api/v1/auth/refresh") response = client.post("/api/v1/auth/refresh")
assert response.status_code == 401 assert response.status_code == 401
assert response.json()["detail"] == "Invalid token type" assert response.json()["detail"] == "Invalid token type"
def test_protected_endpoint_rejects_refresh_token(client):
"""Regression test: Ensure refresh tokens cannot be used to access protected endpoints."""
user_id = "test-user-id"
refresh_token = create_refresh_token({"sub": user_id})
# Attempt to access /auth/me with a refresh token in the cookie
client.cookies.set("access_token", refresh_token)
response = client.get("/api/v1/auth/me")
# Should be rejected with 401
assert response.status_code == 401
assert "Cannot use refresh token for this endpoint" in response.json()["detail"]

View File

@@ -17,9 +17,9 @@ export const registerUnauthorizedCallback = (callback: () => void) => {
// State to manage multiple concurrent refreshes // State to manage multiple concurrent refreshes
let isRefreshing = false let isRefreshing = false
let refreshSubscribers: ((token: string) => void)[] = [] let refreshSubscribers: ((token: string) => void)[] = []
let refreshErrorSubscribers: ((error: any) => void)[] = [] let refreshErrorSubscribers: ((error: unknown) => void)[] = []
const subscribeTokenRefresh = (onSuccess: (token: string) => void, onError: (error: any) => void) => { const subscribeTokenRefresh = (onSuccess: (token: string) => void, onError: (error: unknown) => void) => {
refreshSubscribers.push(onSuccess) refreshSubscribers.push(onSuccess)
refreshErrorSubscribers.push(onError) refreshErrorSubscribers.push(onError)
} }
@@ -30,7 +30,7 @@ const onRefreshed = (token: string) => {
refreshErrorSubscribers = [] refreshErrorSubscribers = []
} }
const onRefreshFailed = (error: any) => { const onRefreshFailed = (error: unknown) => {
refreshErrorSubscribers.forEach((callback) => callback(error)) refreshErrorSubscribers.forEach((callback) => callback(error))
refreshSubscribers = [] refreshSubscribers = []
refreshErrorSubscribers = [] refreshErrorSubscribers = []
@@ -52,7 +52,7 @@ api.interceptors.response.use(
// Wait for the current refresh to complete // Wait for the current refresh to complete
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
subscribeTokenRefresh( subscribeTokenRefresh(
(_token) => resolve(api(originalRequest)), () => resolve(api(originalRequest)),
(err) => reject(err) (err) => reject(err)
) )
}) })
@@ -72,7 +72,7 @@ api.interceptors.response.use(
// Retry the original request // Retry the original request
return api(originalRequest) return api(originalRequest)
} catch (refreshError) { } catch (refreshError: unknown) {
isRefreshing = false isRefreshing = false
onRefreshFailed(refreshError) onRefreshFailed(refreshError)
console.error("Reactive refresh failed:", refreshError) console.error("Reactive refresh failed:", refreshError)