While building a construction management app that needed to handle file uploads and downloads from a React frontend, I ran into one of those seemingly simple tasks that turned into a multi-hour debugging session. I had a Google Cloud Storage bucket set up for storing project recordings, presigned URLs working in my backend, but every time my localhost:3000 development server tried to make requests to the bucket, I'd get hit with CORS errors.
"Easy fix," I thought. "Just add a CORS configuration to the bucket." But what started as a quick gcloud command quickly spiraled into a permissions maze involving service accounts, IAM roles, bucket-level permissions, and the subtle differences between uniform and fine-grained access control.
After wrestling with storage.buckets.update permission denials, switching between personal and service accounts, and discovering that my bucket name had a typo that I'd been living with for months, I finally got everything working. The solution involved not just the CORS configuration itself, but understanding GCS permissions, authentication flows, and access control models.
What You'll Learn
By the end of this article, you'll know how to:
Create and apply CORS configurations to Google Cloud Storage buckets using gcloud
Troubleshoot common permission issues with service accounts and user authentication
Understand the difference between uniform and fine-grained access control
Test and verify your CORS configuration is working properly
Handle authentication switching between personal and service accounts
If you're dealing with CORS issues between your web app and Google Cloud Storage, or if you've ever stared at a "does not have permission to access" error while knowing you're definitely the project owner, this guide will walk you through the complete setup process – including all the permission gotchas I encountered along the way.
Prerequisites
Before we start, make sure you have:
gcloud CLI installed and configured
A Google Cloud Storage bucket created
Basic understanding of CORS concepts
Access to your Google Cloud project (we'll handle permission issues as they come up)
Step 1: Understanding CORS Configuration
CORS (Cross-Origin Resource Sharing) allows web applications running on one domain to access resources from another domain. For Google Cloud Storage, this means configuring your bucket to accept requests from your web application's origin.
A CORS configuration file is a JSON array containing rules that specify:
Origins: Which domains can access your bucket
Methods: Which HTTP methods are allowed (GET, POST, PUT, DELETE, OPTIONS)
Response Headers: Which headers the browser can access
Max Age: How long browsers should cache the CORS preflight response
Step 2: Create Your CORS Configuration File
Create a file named cors-config.json with the following content:
ERROR: [matija@we-hate-copy-pasting.com] does not have permission to access b instance [recorings] (or it may not exist): matija@we-hate-copy-pasting.com does not have storage.buckets.update access to the Google Cloud Storage bucket.
Even though I thought I had the right permissions, my user account lacked the storage.buckets.update permission. Here's how I fixed it:
But got the same permission error for the service account. The solution was to grant the service account the necessary permissions:
bash
# Switch back to your personal account
gcloud auth login your-email@domain.com
# Grant permissions to service account
gcloud projects add-iam-policy-binding your-project-id \
--member="serviceAccount:service-account@project.iam.gserviceaccount.com" \
--role="roles/storage.admin"# Switch back to service account
gcloud auth activate-service-account --key-file=/path/to/service-account.json
Step 4: Verify Your Configuration
Once the command succeeds, verify your CORS configuration:
What started as a simple CORS configuration turned into a comprehensive lesson in Google Cloud Storage permissions, authentication, and access control models. The key takeaways are:
CORS configuration itself is straightforward - it's a simple JSON file and one gcloud command
Permissions are the real challenge - ensure you have storage.buckets.update permission
Authentication matters - know whether you're using your personal account or service account
Double-check the basics - bucket names, project IDs, and exact origins
IAM changes take time - be patient with permission propagation
The gcloud storage buckets update --cors-file command is powerful and flexible, but make sure you have your authentication and permissions sorted first. Once you understand the permission model, updating CORS configurations becomes a breeze.
Remember to test your CORS configuration thoroughly in both development and production environments, and don't forget to include the OPTIONS method for preflight requests. With the right setup, your web application will seamlessly communicate with Google Cloud Storage without any CORS headaches.