Skip to main content

Firebase Storage: Project cover images

Project cover images are uploaded via the app’s API (server-side) to avoid CORS. The browser sends the file to POST /api/projects/[projectKey]/upload-image; the server uploads to the bucket and returns a signed URL. No CORS configuration is required for uploads.

Images are stored at:

project-images/{projectKey}/{timestamp}-{filename}

CORS (required for uploads from browser)​

If you see CORS errors in the console when uploading (e.g. from http://localhost:3000), the Storage bucket must allow your origin. Firebase Storage does not allow cross-origin requests by default.

One-time setup with gsutil​

  1. Install Google Cloud SDK (includes gsutil): https://cloud.google.com/sdk/docs/install

  2. Authenticate and set project:

    gcloud auth login
    gcloud config set project gtc-tools-dev
  3. Find your Storage bucket name. The Firebase Console shows a URL like gtc-tools-dev.firebasestorage.app, but the GCS bucket name is often different. List buckets:

    gsutil ls

    Use the bucket that matches your project (commonly gs://gtc-tools-dev.appspot.com). You can also copy the bucket name from Firebase Console → Storage → Files (bucket is shown at the top).

  4. Apply CORS (replace BUCKET_NAME with the bucket from step 3). The app uses gtc-tools-dev.appspot.com by default, so CORS must be set on that bucket:

    gsutil cors set apps/web/firebase-storage.cors.json gs://BUCKET_NAME

    Example:

    gsutil cors set apps/web/firebase-storage.cors.json gs://gtc-tools-dev.appspot.com
  5. Add production origin to apps/web/firebase-storage.cors.json if you host on a different domain, then run the gsutil cors set command again.

After this, uploads and image loads from the configured origins will work.


Storage rules​

Ensure your Firebase Storage rules allow authenticated users to read and write under project-images/. Example (Firebase Console → Storage → Rules):

rules_version = '2';
service firebase.storage {
match /b/{bucket}/o {
match /project-images/{projectKey}/{allPaths=**} {
allow read: if true;
allow write: if request.auth != null;
}
}
}
  • read: public so project cards can show images without auth.
  • write: only authenticated users can upload (prevents anonymous uploads).

Adjust to match your security requirements (e.g. restrict read to authenticated users if needed).