Skip to content

refactor(medusa): refactor cart ownership checks and update order list query#837

Merged
lukasz-hycom merged 3 commits intomainfrom
fix/medusa_cart-validation-and-orders-fixes
Mar 26, 2026
Merged

refactor(medusa): refactor cart ownership checks and update order list query#837
lukasz-hycom merged 3 commits intomainfrom
fix/medusa_cart-validation-and-orders-fixes

Conversation

@lukasz-hycom
Copy link
Copy Markdown
Contributor

@lukasz-hycom lukasz-hycom commented Mar 25, 2026

Key Changes

  • Remove redundant BFF-side ownership checks in carts and orders
  • Fix missing +item_subtotal field in order list query causing 400 on orders page
  • Remove authService dependency from CartsService, OrdersService, and verifyResourceAccess
  • verifyResourceAccess now only guards one case: unauthenticated access to registered customer resources

Summary by CodeRabbit

  • Refactor

    • Centralized customer access checks for carts and orders: no longer uses a separate auth service; verifies identity via store/admin APIs and request headers.
    • Simplified cart and checkout flows with fewer manual ownership checks.
  • Tests

    • Updated tests and mocks to reflect new access verification via store/admin customer lookups.
  • Bug Fixes

    • Order listing now includes item subtotal.
  • Chores

    • Added changeset for a minor release.

@lukasz-hycom lukasz-hycom self-assigned this Mar 25, 2026
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 25, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
o2s-docs Skipped Skipped Mar 25, 2026 4:54pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7d77453b-da0a-4c23-ae1c-e0eaec233000

📥 Commits

Reviewing files that changed from the base of the PR and between b0e9e47 and 2a66bd3.

📒 Files selected for processing (1)
  • .changeset/sweet-islands-behave.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/sweet-islands-behave.md

Walkthrough

Removed Auth.Service injection from CartsService and OrdersService; ownership checks now validate caller identity via Medusa Store API (store.customer.retrieve) and fall back to Admin API (admin.customer.retrieve) using store/admin headers; tests updated to mock store/admin customer retrievals; order list fields include +item_subtotal.

Changes

Cohort / File(s) Summary
Carts Module
packages/integrations/medusajs/src/modules/carts/carts.service.ts, packages/integrations/medusajs/src/modules/carts/carts.service.spec.ts
Removed Auth.Service injection and authService-based customerId extraction. getCart / addCartItem call verifyResourceAccess with store API headers; manual ownership branches and thrown UnauthorizedException paths removed. Tests now mock sdk.store.customer.retrieve / sdk.admin.customer.retrieve.
Orders Module
packages/integrations/medusajs/src/modules/orders/orders.service.ts, packages/integrations/medusajs/src/modules/orders/orders.service.spec.ts
Removed Auth.Service injection; getOrder authorization now provides store API headers to verifyResourceAccess. Adjusted order list fields to include +item_subtotal (removed duplicate tax_total). Tests updated to use store/admin customer retrieval mocks.
Customer Access Utility
packages/integrations/medusajs/src/utils/customer-access.ts
Changed verifyResourceAccess signature: removed authService, added storeHeaders. When authorization present, calls sdk.store.customer.retrieve to derive caller customer id and compares to target; on mismatch falls back to sdk.admin.customer.retrieve and allows only if target is guest. When no authorization, retains Admin guest-check behavior.
Release Metadata
.changeset/sweet-islands-behave.md
Added changeset to publish a minor version noting behavioral change to ownership checks and the +item_subtotal order-field addition.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant Service as Carts/Orders Service
  participant SDK as Medusa SDK
  participant Store as Medusa Store API
  participant Admin as Medusa Admin API

  Note over Client,Service: Flow when authorization token is provided
  Client->>Service: request + authorization
  Service->>SDK: store.customer.retrieve (with storeHeaders)
  SDK->>Store: GET /store/customers/me
  Store-->>SDK: { customer: { id: callerId } }
  SDK-->>Service: callerId
  alt callerId == targetCustomerId
    Service-->>Client: allow access / proceed
  else callerId != targetCustomerId
    Service->>SDK: admin.customer.retrieve (with adminHeaders)
    SDK->>Admin: GET /admin/customers/:customerId
    Admin-->>SDK: { customer: { id: ..., has_account: bool } }
    SDK-->>Service: targetCustomer (has_account)
    alt target is guest (has_account == false)
      Service-->>Client: allow access
    else
      Service-->>Client: Unauthorized
    end
  end
Loading
sequenceDiagram
  participant Client as Client
  participant Service as Carts/Orders Service
  participant SDK as Medusa SDK
  participant Admin as Medusa Admin API

  Note over Client,Service: Flow when no authorization token provided
  Client->>Service: request (no authorization)
  Service->>SDK: admin.customer.retrieve (with adminHeaders)
  SDK->>Admin: GET /admin/customers/:customerId
  Admin-->>SDK: { customer: { has_account: bool } }
  SDK-->>Service: targetCustomer (has_account)
  alt target is guest (has_account == false)
    Service-->>Client: allow access
  else
    Service-->>Client: Unauthorized
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • marcinkrasowski

Poem

🐰
I nibble headers, peek at store and admin,
If caller matches, onward we spin.
Guest or owner, the path is now clear,
Less paw-scramble, the cart hops near. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is incomplete, missing required sections like 'What does this PR do?', 'Related Ticket(s)', and 'How to test'. Complete the PR description by adding: What does this PR do? section, Related Ticket(s), and detailed How to test steps with setup requirements.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main changes: refactoring cart ownership checks and updating the order list query.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/medusa_cart-validation-and-orders-fixes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/integrations/medusajs/src/modules/carts/carts.service.spec.ts`:
- Line 7: The test still stubs mockAuthService.getCustomerId() and expects the
unauthorized flow, but CartsService no longer uses Auth; update the spec to
remove reliance on mockAuthService and instead stub the new
sdk.admin.customer.retrieve path: add a mock for sdk.admin.customer.retrieve
(returning either a customer for registered flows or throwing/not-found for
guest), update the unauthorized/guest test to assert guest-cart behavior when
retrieve indicates no customer, and add a new test asserting registered-customer
cart behavior when retrieve returns a customer; locate references to
CartsService, mockAuthService.getCustomerId, and sdk.admin.customer.retrieve to
make these changes.

In `@packages/integrations/medusajs/src/modules/carts/carts.service.ts`:
- Around line 149-164: The cart ownership check was removed, which allows
unauthenticated users to add items to other customers' carts; restore the
verification by invoking the same preflight used previously (call getCart(...)
then verifyResourceAccess(...) with the fetched cart and the current
authorization) before calling this.sdk.store.cart.createLineItem; ensure you
reject the request if verifyResourceAccess fails and only proceed to
createLineItem when access is confirmed (apply this in the method wrapping the
createLineItem call and keep existing error handling via handleHttpError).

In `@packages/integrations/medusajs/src/utils/customer-access.ts`:
- Around line 18-23: The current early-return skips ownership validation when an
Authorization header is present; restore owner checking by removing the bypass
and validating that the authenticated customer ID matches the resource's
customer ID after retrieving the resource via sdk.admin.customer.retrieve(...,
adminHeaders). Specifically, in the function containing the
customerId/authorization logic, do not return early on authorization — instead
call sdk.admin.customer.retrieve(customerId, {}, adminHeaders), then compare the
retrieved customer's id (or customer.id on the resource you fetch) to the
authenticated customer id extracted from the Authorization token and return an
unauthorized/empty response if they don't match; alternatively ensure this
ownership check is enforced in custom auth middleware invoked before this
function.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 368869cb-568d-4d34-88ee-36b8d66a45cc

📥 Commits

Reviewing files that changed from the base of the PR and between 988c453 and 0c3e522.

📒 Files selected for processing (5)
  • packages/integrations/medusajs/src/modules/carts/carts.service.spec.ts
  • packages/integrations/medusajs/src/modules/carts/carts.service.ts
  • packages/integrations/medusajs/src/modules/orders/orders.service.spec.ts
  • packages/integrations/medusajs/src/modules/orders/orders.service.ts
  • packages/integrations/medusajs/src/utils/customer-access.ts
💤 Files with no reviewable changes (1)
  • packages/integrations/medusajs/src/modules/orders/orders.service.spec.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
packages/integrations/medusajs/src/modules/carts/carts.service.spec.ts (1)

79-79: 🛠️ Refactor suggestion | 🟠 Major

Remove dead mockAuthService code.

mockAuthService is defined, initialized, and its getCustomerId method is stubbed in several tests, but it is never injected into CartsService (lines 124-129). These stubs have no effect since CartsService no longer depends on Auth.Service. This makes tests misleading—they appear to configure authorization behavior but actually don't.

Clean up by removing mockAuthService entirely and any references to it.

🧹 Remove dead mockAuthService code
-    let mockAuthService: { getCustomerId: ReturnType<typeof vi.fn> };
-        mockAuthService = { getCustomerId: vi.fn() };

And remove all occurrences of:

-            mockAuthService.getCustomerId.mockReturnValue(undefined);
-            mockAuthService.getCustomerId.mockReturnValue('cust_1');

Also applies to: 113-113, 220-220, 248-248, 263-263, 290-290, 315-315

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/integrations/medusajs/src/modules/carts/carts.service.spec.ts` at
line 79, Remove the dead mockAuthService test fixture and all of its uses:
delete the declaration "mockAuthService", any vi.fn() stubs for
mockAuthService.getCustomerId, and any assignments or calls that configure or
reference mockAuthService in the CartsService test setup and individual specs;
since CartsService no longer depends on Auth.Service, ensure you also remove any
leftover imports or local variables related to Auth or mockAuthService so there
are no unused items or misleading stubs remaining in carts.service.spec.ts (look
for occurrences of mockAuthService, getCustomerId, and its vi.fn() setup in
beforeEach/it blocks and remove them).
🧹 Nitpick comments (1)
packages/integrations/medusajs/src/modules/carts/carts.service.spec.ts (1)

148-181: Consider adding test coverage for additional authorization scenarios.

The getCart tests cover:

  1. ✅ Public resource (no customer_id)
  2. ✅ Unauthorized access (customer mismatch with registered user)
  3. ✅ 404 error handling

Missing coverage for the new verifyResourceAccess logic:

  • Authenticated user accessing their own cart (customer IDs match)
  • Authenticated user accessing a guest cart (should succeed for cart merge)
  • Unauthenticated access to a guest cart (guest checkout flow)
  • Unauthenticated access to a registered user's cart (should fail)
🧪 Example test for authenticated owner access
it('should allow access when authenticated customer owns the cart', async () => {
    mockSdk.store.cart.retrieve.mockResolvedValue({ cart: { ...minimalCart, customer_id: 'cust_1' } });
    mockSdk.store.customer.retrieve.mockResolvedValue({ customer: { id: 'cust_1' } });

    const result = await firstValueFrom(service.getCart({ id: 'cart_1' }, 'Bearer token'));

    expect(result?.id).toBe('cart_1');
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/integrations/medusajs/src/modules/carts/carts.service.spec.ts`
around lines 148 - 181, Add tests exercising the verifyResourceAccess branches
in the getCart suite: create one test where mockSdk.store.cart.retrieve returns
a cart with customer_id 'cust_1' and mockSdk.store.customer.retrieve returns {
id: 'cust_1' } to assert getCart succeeds for an authenticated owner; one test
where the cart has no customer_id (guest cart) and an authenticated user calls
getCart to assert success (simulate merge path); one test where cart has no
customer_id and no auth token to assert guest access succeeds; and one test
where cart has customer_id 'cust_other' and no auth (or mismatched auth) to
assert getCart throws UnauthorizedException. Use the existing helpers/mocks
(mockSdk.store.cart.retrieve, mockSdk.store.customer.retrieve,
mockSdk.admin.customer.retrieve, minimalCart) and assert either a successful
result.id or that the call rejects with UnauthorizedException as appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/integrations/medusajs/src/modules/carts/carts.service.spec.ts`:
- Line 79: Remove the dead mockAuthService test fixture and all of its uses:
delete the declaration "mockAuthService", any vi.fn() stubs for
mockAuthService.getCustomerId, and any assignments or calls that configure or
reference mockAuthService in the CartsService test setup and individual specs;
since CartsService no longer depends on Auth.Service, ensure you also remove any
leftover imports or local variables related to Auth or mockAuthService so there
are no unused items or misleading stubs remaining in carts.service.spec.ts (look
for occurrences of mockAuthService, getCustomerId, and its vi.fn() setup in
beforeEach/it blocks and remove them).

---

Nitpick comments:
In `@packages/integrations/medusajs/src/modules/carts/carts.service.spec.ts`:
- Around line 148-181: Add tests exercising the verifyResourceAccess branches in
the getCart suite: create one test where mockSdk.store.cart.retrieve returns a
cart with customer_id 'cust_1' and mockSdk.store.customer.retrieve returns { id:
'cust_1' } to assert getCart succeeds for an authenticated owner; one test where
the cart has no customer_id (guest cart) and an authenticated user calls getCart
to assert success (simulate merge path); one test where cart has no customer_id
and no auth token to assert guest access succeeds; and one test where cart has
customer_id 'cust_other' and no auth (or mismatched auth) to assert getCart
throws UnauthorizedException. Use the existing helpers/mocks
(mockSdk.store.cart.retrieve, mockSdk.store.customer.retrieve,
mockSdk.admin.customer.retrieve, minimalCart) and assert either a successful
result.id or that the call rejects with UnauthorizedException as appropriate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6e0fa77a-7918-4d1b-9818-99115f1e86ef

📥 Commits

Reviewing files that changed from the base of the PR and between 0c3e522 and b0e9e47.

📒 Files selected for processing (5)
  • packages/integrations/medusajs/src/modules/carts/carts.service.spec.ts
  • packages/integrations/medusajs/src/modules/carts/carts.service.ts
  • packages/integrations/medusajs/src/modules/orders/orders.service.spec.ts
  • packages/integrations/medusajs/src/modules/orders/orders.service.ts
  • packages/integrations/medusajs/src/utils/customer-access.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/integrations/medusajs/src/modules/orders/orders.service.ts
  • packages/integrations/medusajs/src/modules/orders/orders.service.spec.ts
  • packages/integrations/medusajs/src/modules/carts/carts.service.ts

@github-actions
Copy link
Copy Markdown
Contributor

Coverage Report for packages/configs/vitest-config

Status Category Percentage Covered / Total
🔵 Lines 78.5% 1734 / 2209
🔵 Statements 77.45% 1824 / 2355
🔵 Functions 74.75% 527 / 705
🔵 Branches 65.93% 1140 / 1729
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/integrations/medusajs/src/modules/carts/carts.service.ts 79.84% 65.9% 77.04% 82.11% 100, 137-142, 183, 219, 261, 280, 297, 346, 362-365, 377-380, 391, 401-405, 425, 448, 473, 494, 512
packages/integrations/medusajs/src/modules/orders/orders.service.ts 85.18% 75% 88.88% 85.18% 113, 125, 129-131
packages/integrations/medusajs/src/utils/customer-access.ts 100% 80% 100% 100%
Generated in workflow #576 for commit 2a66bd3 by the Vitest Coverage Report Action

@lukasz-hycom lukasz-hycom merged commit 880c2df into main Mar 26, 2026
13 checks passed
@lukasz-hycom lukasz-hycom deleted the fix/medusa_cart-validation-and-orders-fixes branch March 26, 2026 08:01
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.

2 participants