Skip to content

firebase deploy silently ignores Application Default Credentials (ADC) / GOOGLE_APPLICATION_CREDENTIALS in CI — throws "Failed to authenticate, have you run firebase login?" despite valid WIF credentials #10726

Description

@alexjbrandtjr-gif

firebase-tools:

Platform:

[REQUIRED] Test case

[REQUIRED] Steps to reproduce

[REQUIRED] Expected behavior

[REQUIRED] Actual behavior

Product: firebase-tools
Version affected: v15.x (confirmed v15.17.0; likely all v15 releases)
Environment: GitHub Actions / any CI using google-github-actions/auth with Workload Identity Federation

Problem statement
When firebase deploy is run in a GitHub Actions environment where authentication was established via google-github-actions/auth with Workload Identity Federation, it throws:

Error: Failed to authenticate, have you run firebase login?
This occurs even though:

GOOGLE_APPLICATION_CREDENTIALS is set to a valid credentials file
gcloud auth print-access-token succeeds and returns a valid token
The service account has full roles/firebase.admin and roles/cloudfunctions.developer IAM bindings
Every other GCP API called in the same CI job (Firestore REST API, Storage REST API, gcloud CLI) authenticates successfully with the same credentials
Root cause analysis

The auth resolution chain in requireAuth.js (paraphrased) is:

  1. --token CLI flag
  2. FIREBASE_TOKEN environment variable
  3. configstore (local login via firebase login)
  4. autoAuth() via google-auth-library
    Step 4 is where it fails silently. autoAuth() calls google-auth-library's GoogleAuth, which itself reads ADC correctly — but firebase-tools wraps this in a hardcoded timeout. If autoAuth() does not resolve within that window (observed in WIF environments where the credential exchange adds latency), firebase-tools catches the timeout and surfaces the generic "have you run firebase login?" error, discarding the actual ADC failure reason.

Critically, GOOGLE_OAUTH_ACCESS_TOKEN is never consulted anywhere in this chain — not as an env-var shortcut, not as a fallback. This is inconsistent with gcloud, which accepts a raw bearer token via that variable directly.

The result is that the only reliable CI workaround in firebase-tools v15 is the deprecated --token flag with a long-lived OAuth 2.0 refresh token (FIREBASE_TOKEN), which contradicts GCP's current security guidance to use short-lived WIF credentials.

Reproduction steps
Set up a GitHub Actions job using google-github-actions/auth@v3 with workload_identity_provider and service_account (standard WIF setup, create_credentials_file: true, export_environment_variables: true).

In the same job, confirm ADC works:

gcloud auth print-access-token # succeeds, returns valid token
curl -H "Authorization: Bearer $(gcloud auth print-access-token)"
"https://firebase.googleapis.com/v1beta1/projects/my-project" # 200 OK
Attempt a deploy:

pnpm exec firebase deploy --only functions:myFunction --project my-project
Observe:

Error: Failed to authenticate, have you run firebase login?
despite steps 2 confirming valid credentials.

Minimal reproduction config (deploy.yml excerpt):

  • uses: google-github-actions/auth@v3
    with:
    workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
    service_account: ${{ vars.GCP_DEPLOY_SERVICE_ACCOUNT }}
    create_credentials_file: true
    export_environment_variables: true # sets GOOGLE_APPLICATION_CREDENTIALS
  • run: |
    gcloud auth print-access-token # ✅ works
    pnpm exec firebase deploy --only functions # ❌ "Failed to authenticate"

Expected behavior
firebase deploy should respect GOOGLE_APPLICATION_CREDENTIALS / ADC as a valid authentication path, consistent with every other Google Cloud SDK and client library. Minimally, one of:

Option A: Honor a GOOGLE_OAUTH_ACCESS_TOKEN environment variable as a direct bearer-token override (identical to gcloud's behavior).

Option B: Remove or significantly increase the timeout on autoAuth() so ADC via WIF credential exchange is given sufficient time to complete.

Option C: Surface the actual ADC error in the thrown exception rather than discarding it and replacing it with the generic "have you run firebase login?" message — this would at minimum allow users to diagnose the real problem.

Workaround
Bypass firebase-tools for Cloud Functions deployment by calling the Cloud Functions v2 REST API directly, using a bearer token from gcloud auth print-access-token:

// generateUploadUrl → upload zip → PATCH each function → poll operations
const token = execSync('gcloud auth print-access-token', { encoding: 'utf8' }).trim();
// Upload source
const { uploadUrl, storageSource } = await fetch(
https://cloudfunctions.googleapis.com/v2/projects/${project}/locations/${region}/functions:generateUploadUrl,
{ method: 'POST', headers: { Authorization: Bearer ${token}, 'Content-Type': 'application/json' }, body: '{}' }
).then(r => r.json());
// PATCH each function to reference the new source
const op = await fetch(
https://cloudfunctions.googleapis.com/v2/projects/${project}/locations/${region}/functions/${name}?updateMask=buildConfig.source,
{ method: 'PATCH', headers: { Authorization: Bearer ${token}, 'Content-Type': 'application/json' },
body: JSON.stringify({ buildConfig: { source: { storageSource } } }) }
).then(r => r.json());
This API accepts any valid GCP bearer token. The google-github-actions/auth WIF credentials work perfectly via this path — only firebase-tools' own auth layer rejects them.

Additional context: This regression likely affects any user who followed GCP's guidance to migrate from long-lived service account keys to Workload Identity Federation in GitHub Actions CI. The symptom (a generic "have you run firebase login?" error with no indication ADC was attempted) makes it appear to be a login issue rather than a timeout/auth-chain-ordering bug, which significantly increases debugging time.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions