Compare commits

...
Author SHA1 Message Date
arafatkatze a2b8ecf8b4 More resiliency 2025-07-10 12:18:24 -06:00
arafatkatze 81521c14ef fix: token refresh logic with firebase 2025-07-10 11:42:50 -06:00
+78 -7
View File
@@ -33,6 +33,7 @@ export class AuthService {
private readonly _authNonce = crypto.randomBytes(32).toString("hex")
private _activeAuthStatusUpdateSubscriptions = new Set<[Controller, StreamingResponseHandler]>()
private _context: vscode.ExtensionContext
private _refreshTimer: NodeJS.Timeout | null = null
/**
* Creates an instance of AuthService.
@@ -199,6 +200,12 @@ export class AuthService {
}
try {
// Clear any active refresh timer
if (this._refreshTimer) {
clearTimeout(this._refreshTimer)
this._refreshTimer = null
}
await this._provider.provider.signOut()
this._user = null
this._authenticated = false
@@ -209,6 +216,17 @@ export class AuthService {
}
}
/**
* Dispose of the AuthService and clean up resources
*/
dispose(): void {
if (this._refreshTimer) {
clearTimeout(this._refreshTimer)
this._refreshTimer = null
}
this._activeAuthStatusUpdateSubscriptions.clear()
}
async handleAuthCallback(token: string, provider: string): Promise<void> {
if (!this._provider) {
throw new Error("Auth provider is not set")
@@ -273,14 +291,43 @@ export class AuthService {
return
}
await this._provider.provider.refreshAuthToken()
this.sendAuthStatusUpdate()
try {
await this._provider.provider.refreshAuthToken()
this.sendAuthStatusUpdate()
} catch (error) {
console.error("Token refresh failed:", error)
throw error // Let caller handle the error
}
}
private setupAutoRefreshAuth(): void {
// Set timeoutDuration to refresh the auth token 5 minutes before it expires
const timeoutDuration = Math.floor(this._user.stsTokenManager.expirationTime - 5 * 60000 - Date.now()) // Milliseconds until 5 minutes before expiration
setTimeout(() => this._autoRefreshAuth(), timeoutDuration)
// Clear any existing timer first
if (this._refreshTimer) {
clearTimeout(this._refreshTimer)
this._refreshTimer = null
}
// Validate user and token manager
if (!this._user?.stsTokenManager?.expirationTime) {
console.warn("No valid expiration time found, skipping auto-refresh setup")
return
}
const expirationTime = this._user.stsTokenManager.expirationTime
const now = Date.now()
const timeUntilExpiry = expirationTime - now
// Set refresh time to 10 minutes before expiry (increased buffer from 5 minutes)
// But ensure minimum of 1 minute delay
const refreshTime = Math.max(timeUntilExpiry - 10 * 60 * 1000, 60000)
// Only set timer if refresh time is reasonable (between 1 minute and 2 hours)
if (refreshTime > 0 && refreshTime < 2 * 60 * 60 * 1000) {
this._refreshTimer = setTimeout(() => this._autoRefreshAuth(), refreshTime)
console.log(`Auth refresh scheduled in ${Math.round(refreshTime / 60000)} minutes`)
} else {
console.warn(`Invalid refresh time: ${Math.round(refreshTime / 60000)} minutes, skipping auto-refresh setup`)
}
}
private async _autoRefreshAuth(): Promise<void> {
@@ -288,8 +335,32 @@ export class AuthService {
console.warn("No user is authenticated, skipping auth refresh")
return
}
await this.refreshAuth()
this.setupAutoRefreshAuth() // Reschedule the next auto-refresh
let retries = 3
let lastError: Error | null = null
while (retries > 0) {
try {
await this.refreshAuth()
console.log("Auth token refreshed successfully")
// Only reschedule if refresh was successful
this.setupAutoRefreshAuth()
return
} catch (error) {
lastError = error as Error
retries--
console.warn(`Auth refresh attempt failed (${3 - retries}/3): ${lastError.message}`)
if (retries > 0) {
// Wait 5 seconds before retrying
await new Promise((resolve) => setTimeout(resolve, 5000))
}
}
}
// All retries failed
console.error(`Auth refresh failed after 3 attempts. Last error: ${lastError?.message}`)
// Don't reschedule on complete failure - user will need to re-authenticate
}
/**