fix(auth): Resolve lint regressions and add security regression test
This commit is contained in:
@@ -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"]
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user