Firebase Deploy "Permission Denied"

Firebase deploy fails with permission errors — IAM, login, or project mismatch.

You run firebase deploy locally or in CI and it errors:

Error: HTTP Error: 403, The caller does not have permission
Error: Request to https://firebase.googleapis.com/... had HTTP Error: 403

Or more bluntly:

Error: Failed to authenticate, have you run firebase login?

The fix isn’t in the firebase deploy command — it’s in the identity chain behind it: your local Google account → project mapping → that account’s IAM roles on GCP. Any link missing = permission denied.

Common causes

Ordered by hit rate, highest first.

1. Logged into personal account, project is under work account

Most common. firebase login defaulted to personal@gmail.com, but the project is in you@company.com’s GCP organization — personal account has zero access.

How to spot it: firebase login:list shows current account; compare to which org/account owns the project in GCP console.

2. Account lacks Firebase Hosting Admin role

Account can see the project but can’t deploy. Common for new hires — SRE added Viewer but forgot the deploy roles.

How to spot it: GCP IAM → select project → find your email → review role list.

3. Wrong project ID in .firebaserc

{
  "projects": {
    "default": "my-project-prod"  // real ID is my-project-prod-x9q
  }
}

CLI tries to deploy to a project that doesn’t exist or you can’t access.

How to spot it: firebase projects:list to see what you can access; compare to .firebaserc.

4. CI uses expired / wrong service account key

CI auth via GOOGLE_APPLICATION_CREDENTIALS or FIREBASE_TOKEN. Key was deleted, rotated, or had permissions revoked.

How to spot it: CI logs 401/403, local deploy of the same project works.

5. Required API not enabled

Cloud Build API / Cloud Functions API / Cloud Run API disabled. CLI prompts to enable, but nobody confirms in CI.

How to spot it: Error contains “API has not been used” or “is disabled.”

6. Org policy blocks personal accounts

Some GCP orgs enforce “External members not allowed” — gmail.com accounts can be invited but not deploy.

How to spot it: Error contains “principalType is not allowed by the organization policy.”

Shortest path to fix

Step 1: Audit the identity chain

# 1. Current account
firebase login:list

# 2. Projects this account can access
firebase projects:list

# 3. Active project alias from .firebaserc
cat .firebaserc

# 4. Active deploy target
firebase use   # shows current

Cross-check: account → project visible in the list → .firebaserc ID present in the list → use is the intended target.

Step 2: Log in with the right account

firebase logout
firebase login   # pick work account in browser
firebase login:list  # confirm work email

For multi-account switching, use --account:

firebase deploy --account=you@company.com --project=my-prod

Step 3: Have admin add IAM roles

Minimum for Hosting + Functions deploy:

- Firebase Hosting Admin     (roles/firebasehosting.admin)
- Cloud Functions Admin      (roles/cloudfunctions.admin)
- Service Account User       (roles/iam.serviceAccountUser)
- Firebase Admin             (roles/firebase.admin)  # blunt all-in-one

Admin goes to IAM → project → Grant Access → add your email + the roles.

Step 4: Fix .firebaserc

firebase use --add  # interactive picker
# or edit by hand:
{
  "projects": {
    "default": "my-project-prod-x9q",
    "staging": "my-project-staging-a3p"
  }
}
firebase use staging  # switch to staging
firebase deploy --only hosting

Step 5: CI uses a service account

Never run firebase login with a personal account in CI. Create a service account:

# 1. GCP IAM → Service Accounts → Create
# 2. Grant the SA the roles above
# 3. Download JSON key

# CI (GitHub Actions example)
env:
  GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GCP_SA_KEY }}
steps:
  - run: |
      echo "${GOOGLE_APPLICATION_CREDENTIALS}" > /tmp/sa.json
      export GOOGLE_APPLICATION_CREDENTIALS=/tmp/sa.json
      firebase deploy --project my-project-prod --non-interactive

Or FIREBASE_TOKEN (legacy):

firebase login:ci  # generate token, store in CI secret
firebase deploy --token "$FIREBASE_TOKEN"

Step 6: Enable required APIs

gcloud services enable \
  firebase.googleapis.com \
  cloudfunctions.googleapis.com \
  cloudbuild.googleapis.com \
  artifactregistry.googleapis.com \
  --project=my-project-prod

Or visit API Library and enable them all.

Prevention

  • Wiki page on day-one onboarding: “deploying Firebase requires these IAM roles”
  • Personal projects → personal Google account; work → work — never mix; use browser profile isolation
  • Commit .firebaserc with comments per project ID (which env)
  • Always use a service account in CI; never personal token
  • Rotate service-account keys every 90 days; calendar it
  • Prefer firebase use staging --reload over manual .firebaserc edits — more reproducible
  • Dry-run before deploy: firebase deploy --only hosting --dry-run shows what would change

Tags: #Backend #Debug #Troubleshooting #Firebase