diff --git a/firebase-vscode/CHANGELOG.md b/firebase-vscode/CHANGELOG.md index 481a0d8a177..530a84f3e47 100644 --- a/firebase-vscode/CHANGELOG.md +++ b/firebase-vscode/CHANGELOG.md @@ -1,6 +1,7 @@ ## NEXT -- [Fixed] Fixed an issue where command would be executed against directory default project instead of the currently selected project. +- [Fixed] Fixed an issue where commands would be executed against directory default project instead of the currently selected project. +- [Fixed] Fixed an issue where expired auth tokens would be used. ## 0.10.0 diff --git a/src/apiv2.ts b/src/apiv2.ts index de6e7c11d5f..72a2fa3defb 100644 --- a/src/apiv2.ts +++ b/src/apiv2.ts @@ -127,7 +127,9 @@ export function setAccessToken(token = ""): void { * @returns An access token */ export async function getAccessToken(): Promise { - if (accessToken) { + const valid = auth.haveValidTokens(refreshToken, []); + const usingADC = !auth.loggedIn(); + if (accessToken && (valid || usingADC)) { return accessToken; } const data = await auth.getAccessToken(refreshToken, []); @@ -462,6 +464,16 @@ export class Client { this.logResponse(res, body, options); if (res.status >= 400) { + if (res.status === 401 && this.opts.auth) { + // If we get a 401, access token is expired or otherwise invalid. + // Throw it away and get a new one. We check for validity before using + // tokens, so this should not happen. + logger.debug( + "Got a 401 Unauthenticated error for a call that required authentication. Refreshing tokens.", + ); + setAccessToken(); + setAccessToken(await getAccessToken()); + } if (options.retryCodes?.includes(res.status)) { const err = responseToError({ statusCode: res.status }, body) || undefined; if (operation.retry(err)) { diff --git a/src/auth.ts b/src/auth.ts index b01320e6b56..493d3b52914 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -560,7 +560,11 @@ export function findAccountByEmail(email: string): Account | undefined { return getAllAccounts().find((a) => a.user.email === email); } -function haveValidTokens(refreshToken: string, authScopes: string[]) { +export function loggedIn() { + return !!lastAccessToken; +} + +export function haveValidTokens(refreshToken: string, authScopes: string[]) { if (!lastAccessToken?.access_token) { const tokens = configstore.get("tokens"); if (refreshToken === tokens?.refresh_token) { @@ -575,8 +579,15 @@ function haveValidTokens(refreshToken: string, authScopes: string[]) { // To avoid token expiration in the middle of a long process we only hand out // tokens if they have a _long_ time before the server rejects them. const isExpired = (lastAccessToken?.expires_at || 0) < Date.now() + FIFTEEN_MINUTES_IN_MS; - - return hasTokens && hasSameScopes && !isExpired; + const valid = hasTokens && hasSameScopes && !isExpired; + if (hasTokens) { + logger.debug( + `Checked if tokens are valid: ${valid}, expires at: ${lastAccessToken?.expires_at}`, + ); + } else { + logger.debug("No OAuth tokens found"); + } + return valid; } function deleteAccount(account: Account) {