Add Vercel OIDC auth and Presigned URLs (#1056)
* Add Vercel OIDC auth * up * header * up * prioritize token * normalize storeId in OIDC auth resolution BLOB_STORE_ID and the storeId option are accepted in either store_<id> or <id> form (Vercel env pull writes the prefixed form), and may be mixed-case. resolveBlobAuth was passing those through verbatim, so the storeId in API headers and CDN host subdomains could be malformed — e.g. blob.get against a private store with `store_WdsHBk1w9fDO4vPW` built `https://store_WdsHBk1w9fDO4vPW.private.blob.vercel-storage.com/...` and 404'd. The RW path was unaffected because parseStoreIdFromReadWriteToken yields a bare lowercase id from the token's structure. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * preserve case when normalizing storeId The first pass also lowercased — that breaks API requests, since the Vercel Blob API is case-sensitive on the storeId (header and bearer parsing). The CDN host accepts either case, so prefix-strip alone is sufficient and works for both consumers. Verified end-to-end against a private store: blob get and blob list both succeed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * add oidcToken option * minor version * Vercel Presigned URLs (#1057) * presigned urls * up * normalize * fix * update to new signing string * [wip] presigned url version of handleUpload (#1059) * [wip] presigned url version of handleUpload * up * up * up * add presigned urls for mpu * update options shape * webhook signature * update example * up * up * up * change to operation * up * up * verify webhook signature * up * callbackUrl * non-null * presigned url opts * new delegation token + url opts * dont lowercase store id * validUntil instead of ttlSeconds * up * up * Add 'delete' to DelegationOperation for presigned DELETE URLs (#1061) Mirrors the API-side change that adds `delete` to the issue_signed_token allowed operations. `presignUrl` now signs canonical `operation=delete\npathname=...` against the public blob object URL (same host shape as `get`/`head`, just used with HTTP DELETE). Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * change upload to put * delete * up * presigned url payload * update app * fix * docs * refactor presign url * up * up * up * add head * up * add params to url * add keys first * token payload * add buildPresignedGetUrl * up * presignUrl returns url, not accepted in sdk methods * up * up * feat(blob): presigned HEAD & DELETE URLs (#1064) * feat(blob): presigned DELETE URLs Wires the `'delete'` DelegationOperation (added in #1061, since rebased out of elliot/presigned-urls) through `presignUrl`. A token issued with `operations: ['delete']` can now mint a presigned `DELETE /?pathname=…` against the control-plane API. - `PresignDeleteUrlOptions` accepts `pathname`, optional `validUntil`, optional `ifMatch`. Upload-only fields are rejected at the type level. - `presign()` gates on the delegation scope including `'delete'`. - `buildPresignedDeleteUrl()` mirrors the PUT URL shape; the HTTP method is the discriminator (canonical signing string carries `operation=delete`). - `buildPresignCanonicalQueryEntries()` for `delete` emits only `validUntil` (when below the delegation ceiling) and `ifMatch`. - E2E test route + delete button on the presigned-upload demo page. Based on `elliot/presigned-urls`, not `main`. * feat(blob): presigned HEAD URLs (#1065) `HEAD` mirrors `GET` against the blob object host (`<storeId>.<access>.blob.vercel-storage.com/<pathname>`); the URL shape is identical and the HTTP method is the discriminator. `operation=head` goes into the canonical signing string so a GET-signed URL cannot be replayed as a HEAD (and vice versa). - `'head'` added to `DelegationOperation`. - `PresignHeadUrlOptions` — same shape as `PresignGetUrlOptions` (`pathname`, optional `validUntil`). - `presign()` gates on the delegation scope including `'head'`. - `presignUrl()` reuses `buildPresignedGetUrl()` for `operation: 'head'`. - `buildPresignCanonicalQueryEntries()` for `head` emits only `validUntil` (when below the delegation ceiling) — same as `get`. - E2E test route + HEAD button on the presigned-upload demo page. Stacked on `falcoagustin/presigned-delete-impl` (#1064). * environment error * up * cleanup --------- Co-authored-by: Agustin Falco <agusfalco_11@hotmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * up * rm dead code * throw on manual token * up * up --------- Co-authored-by: Agustin Falco <agusfalco_11@hotmail.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
E
Elliot Dauber committed
20eeaffead76d8e1a0e8a11108cca5a4e0596974
Parent: f23cb89
Committed by GitHub <noreply@github.com>
on 5/18/2026, 8:37:28 PM