storage: V4 getSignedUrl sorts canonical headers with localeCompare, so they disagree with X-Goog-SignedHeaders
Maintainers usually reply within 1 day
@itsrayeedscodespace is already working on this.
Since Nov 8, 2026.
- #9841 by @itsrayeedscodespace — open
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 82/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- node.js, typescript
Research direction
Start in handwritten/storage/src/signer.ts, at URLSigner.getCanonicalHeaders, and compare its header ordering with the plain .sort() used for signedHeaders. Check the storage signer tests for coverage of header names containing - and _ and for locale-sensitive ordering. Done when the canonical headers block follows code point order and matches the signed headers list.
Written by the indexing model from the issue text.
Description
Please make sure you have searched for information in the following guides.
- Search the issues already opened: https://github.com/GoogleCloudPlatform/google-cloud-node/issues
- Search StackOverflow: http://stackoverflow.com/questions/tagged/google-cloud-platform+node.js
- Check our Troubleshooting guide: https://github.com/googleapis/google-cloud-node/blob/main/docs/troubleshooting.md
- Check our FAQ: https://github.com/googleapis/google-cloud-node/blob/main/docs/faq.md
- Check our libraries HOW-TO: https://github.com/googleapis/gax-nodejs/blob/main/client-libraries.md
- Check out our authentication guide: https://github.com/googleapis/google-auth-library-nodejs
- Check out handwritten samples for many of our APIs: https://github.com/GoogleCloudPlatform/nodejs-docs-samples
- Check the API's issue tracker: https://cloud.google.com/support/docs/issue-trackers
Library Name
@google-cloud/storage
A screenshot that you have tested with "Try this API".
Not applicable: V4 URL signing happens entirely in the client library; no API call is involved.
Link to the code that reproduces this issue. A link to a public Github Repository or gist with a minimal reproduction.
https://gist.github.com/trackoor/dc977f474cf9a692628c158959bbef2c
A step-by-step description of how to reproduce the issue, based on the linked reproduction.
npm install(installs @google-cloud/storage 8.4.0), Node.js v26.13.0 (full ICU), Linux.node index.jsprints the canonical request that gets signed, forextensionHeaders: {"x-goog-meta-a_b": "1", "x-goog-meta-a-b": "2"}:
GET
/test-bucket/test-object
X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test%40example.iam.gserviceaccount.com%2F20261107%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20261107T105715Z&X-Goog-Expires=60&X-Goog-SignedHeaders=host%3Bx-goog-meta-a-b%3Bx-goog-meta-a_b
host:storage.googleapis.com
x-goog-meta-a_b:1
x-goog-meta-a-b:2
host;x-goog-meta-a-b;x-goog-meta-a_b
UNSIGNED-PAYLOAD
LANG=lt_LT.UTF-8 node index.js ltdoes the same forx-goog-meta-yandx-goog-meta-j:
host:storage.googleapis.com
x-goog-meta-y:1
x-goog-meta-j:2
host;x-goog-meta-j;x-goog-meta-y
A clear and concise description of what the bug is, and what you expected to happen.
The canonical headers block is in a different order from the signed headers list in the same canonical request, so GCS computes a different signature and rejects the URL. Expected: canonical headers in code point order, matching X-Goog-SignedHeaders:
host:storage.googleapis.com
x-goog-meta-a-b:2
x-goog-meta-a_b:1
host;x-goog-meta-a-b;x-goog-meta-a_b
A clear and concise description WHY you expect this behavior, i.e., was it a recent change, there is documentation that points to this behavior, etc. **
The V4 canonical request docs say headers are sorted by name "using a lexicographical sort by code point value": https://cloud.google.com/storage/docs/authentication/canonical-requests
URLSigner.getCanonicalHeaders in handwritten/storage/src/signer.ts (line 401 on main at 97b0d64daa8ea9407756aee646b8ac1bf19aec80) sorts with a[0].localeCompare(b[0]), which puts _ before - and follows the process locale, while signedHeaders uses a plain .sort().
Credit: https://ucsbplse.github.io/
- Dominant language
- TypeScript
- Stars
- 3.2k
- Forks
- 732
- Avg merge
- 3d 7h
- Merged PRs (30d)
- 117
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from googleapis/google-cloud-node
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
googleapis/google-cloud-node#9854 ·
Maintainers usually reply within 1 day
-
pubsub: "Operation attempted on ended Span" when a modack is flushed after the message was ackedOpenapi: pubsub
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
googleapis/google-cloud-node#9853 ·
Maintainers usually reply within 1 day
-
firestore: getPartitions() emits gax AutopaginateTrueWarning in every processPossibly taken @TheRealDanii claimed this 9 days ago. Openapi: firestore
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
googleapis/google-cloud-node#9736 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 82/100
googleapis/google-cloud-node#9723 ·
Maintainers usually reply within 1 day
-
spanner: requiring @google-cloud/spanner stops the process from exiting on SIGTERM/SIGINTMay be free again @alkatrivedi claimed this 31 days ago, and no pull request is open. Openapi: spanner
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
googleapis/google-cloud-node#9513 · 1 reaction · 1 assignee ·
Maintainers usually reply within 1 day
All issues in googleapis/google-cloud-node
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
pieterjanscheir/belgica#201 ·
Maintainers usually reply within 1 day
-
accessibility
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
numerique-gouv/lasuite-landingpage#311 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
oxc-project/tsgolint#1362 ·
Maintainers usually reply within 1 day
-
bug external xai
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
langchain-ai/langchain#41854 ·
Maintainers usually reply within 1 day
-
ready-for-agent
Difficulty 1/5 1-3 hours Newbie friendliness 72/100
nemchik/biome-plugin-suitescript#137 ·
Maintainers usually reply within 1 day