fix: prevent race conditions in token operations and auth flows
Backend: - Refresh token rotation: use atomic UPDATE...WHERE revoked_at IS NULL to prevent concurrent refresh requests from both succeeding - Account invite codes: SELECT FOR UPDATE to prevent double-spend - Platform invite codes: SELECT FOR UPDATE to prevent double-spend - Password reset tokens: SELECT FOR UPDATE to prevent double-use - Email verification tokens: SELECT FOR UPDATE to prevent double-use Frontend: - Token refresh subscriber arrays: swap before iterating so a throwing callback doesn't leave the queue in a dirty state Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -75,15 +75,19 @@ let refreshSubscribers: ((token: string) => void)[] = []
|
||||
let refreshFailSubscribers: ((error: unknown) => void)[] = []
|
||||
|
||||
function onRefreshed(token: string) {
|
||||
refreshSubscribers.forEach(cb => cb(token))
|
||||
// Swap arrays before iterating — if a callback throws, the arrays
|
||||
// are already cleared so the next refresh cycle starts clean.
|
||||
const subscribers = refreshSubscribers
|
||||
refreshSubscribers = []
|
||||
refreshFailSubscribers = []
|
||||
subscribers.forEach(cb => cb(token))
|
||||
}
|
||||
|
||||
function onRefreshFailed(error: unknown) {
|
||||
refreshFailSubscribers.forEach(cb => cb(error))
|
||||
const failSubscribers = refreshFailSubscribers
|
||||
refreshSubscribers = []
|
||||
refreshFailSubscribers = []
|
||||
failSubscribers.forEach(cb => cb(error))
|
||||
}
|
||||
|
||||
// Response interceptor - handle token refresh
|
||||
|
||||
Reference in New Issue
Block a user