Skip to content

fix: passing ownership cookie during calculation - #220

Merged
lucvysk merged 2 commits into
mainfrom
fix/ownership-cookie
Aug 11, 2026
Merged

fix: passing ownership cookie during calculation#220
lucvysk merged 2 commits into
mainfrom
fix/ownership-cookie

Conversation

@lucvysk

@lucvysk lucvysk commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

What problem is this solving?

Shoppers were seeing their own clientProfileData and shippingData masked
("receiverName": "T***", "postalCode": "***01") after they had already
entered that data. Once a cart reached this state it could not be recovered.

The cause is the CheckoutOrderFormOwnership cookie, which is the only
credential that unmasks personal data in an order form — an admin token does
not work. Checkout mints it when personal data is written, and rotates it on
every subsequent write. We were losing it in three ways:

  1. An empty ownership cookie was overwriting a valid one. Checkout returns
    CheckoutOrderFormOwnership= (empty) whenever a cart is created, with the
    same domain and path as a real token, so forwarding it erased the ownership
    the shopper already held.
  2. A newly issued ownership was not visible to the rest of the request.
    @withOwnerId snapshots the value from the incoming request, so any Checkout
    call after a rotation kept authenticating with the stale token and got masked
    data back.
  3. updateOrderFormShipping discarded the rotation entirely. It used post,
    which hides response headers, so the token minted by the shippingData
    attachment never reached the browser.

The orderForm query also skipped cookie forwarding whenever
enableOrderFormOptimization was false. That reasoning holds for
checkout.vtex.com (store-graphql sets it) but not for the ownership cookie,
which no other app sets, so it is now always forwarded.

Verified against the published app for contrast: the same mutation on main
emits zero ownership cookies and the cart stays masked permanently.

How should this be manually tested?

Workspace

In a normal browser session (the cookie is httpOnly, so it is only visible in
DevTools → Application → Cookies, never in document.cookie):

  1. Create a cart: /checkout/cart/add/?sku=1&qty=1&seller=1&sc=1.
    CheckoutOrderFormOwnership is present but empty — expected, Checkout blanks
    it on cart creation.
  2. Run updateSelectedAddress (or set an address in checkout). The response
    should carry set-cookie: CheckoutOrderFormOwnership=<non-empty> and the
    cookie should now hold a real value.
  3. Read the cart back at /api/checkout/pub/orderForm/{orderFormId}. The
    address must come back unmasked.
  4. Repeat with updateOrderFormProfile; the token rotates and the profile stays
    unmasked.

Use a cart created after linking. Carts broken before the fix cannot be
recovered, because their token was minted and discarded.

Notes

Scope. Only attachments/shippingData and attachments/clientProfileData
rotate the ownership token; both are covered. items, coupons, paymentData,
checkIn, profile, marketingData, clientPreferencesData, openTextField,
itemsOrdination and messages/clear echo the same value back, so there is
nothing to relay for them. This is observed behaviour rather than a documented
contract — if Checkout starts rotating elsewhere, this would regress silently.

Client middleware. keepOwnership captures the token from every Checkout
response into vtex.ownerId. This covers verbs with no raw variant — notably
patch, used by addItem/updateItems — which cannot read their own response
headers from the calling method. It updates the in-process context only; writing
to the browser remains forwardCheckoutCookies's job.

Dependency. @vtex/api moves 6.50.1 → 6.51.0 for middlewares support in
InstanceOptions.

Out of scope. Checkout blanking the cookie on cart creation is unchanged —
when the browser calls /api/checkout/pub/orderForm directly, this app is not in
the request path and cannot intercept it. Addressing that needs a Checkout-side
change. Reads also cannot mint ownership by design: an orderFormId is not a
secret, so granting ownership on read would let anyone holding an ID unmask
another shopper's PII.

Follow-up. replaceDomain derives the cookie domain from x-forwarded-host.
On a custom storefront domain this could diverge from the domain Checkout uses
and produce two cookies of the same name — and Checkout honours the last one,
which re-masks the data. Worth one test on a custom-domain account.

@lucvysk
lucvysk requested a review from a team as a code owner August 10, 2026 14:11
@vtex-io-ci-cd

vtex-io-ci-cd Bot commented Aug 10, 2026

Copy link
Copy Markdown

Hi! I'm VTEX IO CI/CD Bot and I'll be helping you to publish your app! 🤖

Please select which version do you want to release:

  • Patch (backwards-compatible bug fixes)

  • Minor (backwards-compatible functionality)

  • Major (incompatible API changes)

And then you just need to merge your PR when you are ready! There is no need to create a release commit/tag.

  • No thanks, I would rather do it manually 😞

@vtex-io-docs-bot

vtex-io-docs-bot Bot commented Aug 10, 2026

Copy link
Copy Markdown

Beep boop 🤖

I noticed you didn't make any changes at the docs/ folder

  • There's nothing new to document 🤔
  • I'll do it later 😞

In order to keep track, I'll create an issue if you decide now is not a good time

  • I just updated 🎉🎉

jeffersontuc
jeffersontuc previously approved these changes Aug 10, 2026

@jeffersontuc jeffersontuc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM ✅

@huandrey huandrey left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline Code Review — PR #220 · fix: passing ownership cookie during calculation

0 blocker · 2 warning · 1 nit

CI verde (build, lint, tests, CodeQL). Todos os findings foram ancorados inline — nada ficou de fora do diff.

Comment thread node/clients/ownership.ts
Comment thread node/clients/checkout.ts
Comment thread node/clients/checkout.ts
@lucvysk
lucvysk merged commit a39f0ac into main Aug 11, 2026
7 checks passed
@lucvysk
lucvysk deleted the fix/ownership-cookie branch August 11, 2026 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants