You can release a Chrome extension from GitHub Actions without saving a Google service-account key or OAuth refresh token in repository secrets. The workflow proves its identity to Google Cloud with a GitHub OpenID Connect (OIDC) token. Workload Identity Federation exchanges that token for short-lived credentials. Those credentials impersonate a service account that you have authorized in the Chrome Web Store Developer Dashboard. The workflow then calls Chrome Web Store API v2 to upload and submit the package.
“No stored secret” means no persisted, long-lived credential. Short-lived tokens still exist at runtime, but they expire and are never kept in GitHub. One timing note: the archived v1 API reference gives 2026-10-15 as the end of v1 support, so build on v2.
How the keyless chain fits together
- The GitHub job requests an OIDC token (this needs the
id-token: writepermission). - A Google Cloud workload identity provider validates the token and checks your attribute condition.
- The federated identity impersonates a service account.
- That service account’s email has been added to your Chrome Web Store publisher account, so API calls are accepted as you.
- The job uploads the zip and calls publish.
Google’s documentation says Workload Identity Federation “eliminates the maintenance and security burden associated with service account keys.” GitHub’s guide, Configuring OpenID Connect in Google Cloud Platform, describes the same goal: workflows access Google Cloud without storing the credentials as long-lived GitHub secrets.
Choosing a credential approach
| Approach | Long-lived secret in GitHub? | Trade-off |
|---|---|---|
| OIDC + Workload Identity Federation + service-account impersonation | No | Needs one-time Google Cloud IAM setup and a carefully written trust condition. Best fit for GitHub-hosted CI. |
| Service-account JSON key | Yes | Described in Chrome’s service-account guide as an option, but it is a persistent private key you must protect and rotate. Google recommends federation for external workloads where possible. |
| OAuth client + refresh token | Yes | The tutorial in Use the Chrome Web Store API. It also depends on durable credential material. |
One-time setup
1. Create the service account and authorize it in Chrome
In the Google Cloud project you want to use, enable the Chrome Web Store API and create a service account. Then open the Chrome Web Store Developer Dashboard and add the service account’s email under Account. The service-account guide currently says a publisher can add only one service account, so decide which project and account will own this role before you start. Check that the publisher account and Google Cloud project are the intended ones.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitches#1 Best Overall
2. Create a workload identity pool and GitHub provider
Create a pool and an OIDC provider whose issuer is GitHub’s token service. Map the claims you want to test and add an attribute condition. A sketch with gcloud (replace the placeholders):
gcloud iam workload-identity-pools create github
--project=PROJECT_ID --location=global
gcloud iam workload-identity-pools providers create-oidc github-provider
--project=PROJECT_ID --location=global
--workload-identity-pool=github
--issuer-uri="https://token.actions.githubusercontent.com"
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository"
--attribute-condition="assertion.repository == 'OWNER/REPO'"
The condition is the security boundary. GitHub’s guide cautions that trust conditions must keep untrusted repositories from obtaining credentials. Without one, workflows from other repositories may be able to federate. Tighten the condition further if you can, for example to a specific ref or a GitHub environment. If your workflow uses environments, add protection rules such as required reviewers as an extra control.
3. Let the federated identity impersonate the service account
gcloud iam service-accounts add-iam-policy-binding
SA_NAME@PROJECT_ID.iam.gserviceaccount.com
--role=roles/iam.workloadIdentityUser
--member="principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github/attribute.repository/OWNER/REPO"
The service account needs no Google Cloud roles for Chrome Web Store calls. Its authority comes from being listed in the Developer Dashboard.
4. Meet the first-publication requirements
Per the API usage guide, you need 2-step verification to publish or update an extension. A new item also needs its Store Listing and Privacy tabs completed before it can be published. The API updates an existing item, so create the item once in the dashboard first.
Rank #3
The workflow
Keep id-token: write on the release job only. The provider path, service account, publisher ID and extension ID are identifiers, not secrets, so store them as repository or environment variables.
name: release
on:
push:
tags: ['v*']
jobs:
publish:
runs-on: ubuntu-latest
environment: chrome-web-store
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- run: cd extension && zip -r ../extension.zip .
- id: auth
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ vars.WIF_PROVIDER }}
service_account: ${{ vars.WIF_SERVICE_ACCOUNT }}
token_format: access_token
access_token_scopes: https://www.googleapis.com/auth/chromewebstore
- name: Upload
run: |
curl -fsS -X POST
-H "Authorization: Bearer ${{ steps.auth.outputs.access_token }}"
-T extension.zip
"https://chromewebstore.googleapis.com/upload/v2/publishers/${{ vars.CWS_PUBLISHER_ID }}/items/${{ vars.CWS_EXTENSION_ID }}:upload"
- name: Submit for review
run: |
curl -fsS -X POST
-H "Authorization: Bearer ${{ steps.auth.outputs.access_token }}"
-H "Content-Length: 0"
"https://chromewebstore.googleapis.com/v2/publishers/${{ vars.CWS_PUBLISHER_ID }}/items/${{ vars.CWS_EXTENSION_ID }}:publish"
Pin the action to the major version or commit SHA you have reviewed, and confirm current input names in the action’s own documentation. The endpoint paths follow the resource names in the media.upload and publishers.items.publish references. Check those pages for the exact current request shape.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.What upload and publish actually do
Upload
The upload method sends a package to an existing item. The publisher ID and extension ID are part of the item’s resource name. Raise version in manifest.json before packaging; the usage guide says upload fails if the version was not increased. Deriving the version from the release tag, and failing the build if the two disagree, avoids this class of error.
Publish
By default, publish submits the item for review, and it goes live after approval. Setting the publish type to STAGED_PUBLISH leaves an approved submission staged until you take a later action in the dashboard. A skipReview option exists, but it is only a request. The API can return a validation error when the item requires review. Treat the workflow as automating upload and submission, not as guaranteeing instant availability, because Chrome Web Store review and policy still apply.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchQuick Recap
Best Value
Limits and cautions
- Use v2. The v2 reference says v2 supports service accounts. The archived v1 reference says v1 is deprecated and supported only until 2026-10-15. As of 2026-10-06 that is days away.
- Intended use. The API reference says the API is primarily meant for personal use on your own extensions. It also notes that “verified” status may not be available to apps using the Chrome Web Store write scope, and says this does not block API use.
- Scope of authority. The service account can manage items belonging to the publisher account, so protect the release path with a restrictive trust condition, environment approvals, and tag or branch rules.
- Re-verify limits. Service-account limits, such as the one-per-publisher cap, are current as of the Chrome guide’s present text and may change.
Troubleshooting
- Token exchange denied: the attribute condition probably does not match the token’s claims. Compare
assertion.repositoryand the subject claim to what the run actually presents. Also check thatid-token: writeis set on that job. - Impersonation denied: the
principalSetmember in the IAM binding must use the project number and the same mapped attribute as your provider. - Chrome API returns a permission error: confirm the service account’s email was added under Account in the Developer Dashboard, and that the Chrome Web Store API is enabled in the project.
- Upload rejected: check that the manifest version is higher than the one currently on the item.
- Publish returns a validation error: the item may require review, so drop
skipReviewand use the default submission.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




