docs: improve CORS troubleshooting guide (#14194)

This commit is contained in:
Shahed Nasser
2025-12-03 08:45:21 +02:00
committed by GitHub
parent 00052b9e50
commit fe3c28488c
10 changed files with 563 additions and 25 deletions

View File

@@ -1641,10 +1641,10 @@ import { createOptionsInStrapiStep } from "./steps/create-options-in-strapi"
import { useQueryGraphStep } from "@medusajs/medusa/core-flows"
import {
CreateOptionValuesInStrapiInput,
createOptionValuesInStrapiStep
createOptionValuesInStrapiStep,
} from "./steps/create-option-values-in-strapi"
import {
updateProductOptionValuesMetadataStep
updateProductOptionValuesMetadataStep,
} from "./steps/update-product-option-values-metadata"
export type CreateOptionsInStrapiWorkflowInput = {
@@ -2121,7 +2121,7 @@ export const createVariantsInStrapiWorkflow = createWorkflow(
})
const strapiVariants = when({
variants
variants,
}, (data) => !!(data.variants[0].product as any)?.strapi_product)
.then(() => {
const variantImages = transform({
@@ -2158,7 +2158,7 @@ export const createVariantsInStrapiWorkflow = createWorkflow(
const variantsData = transform({
variants,
strapiVariantImages,
strapiVariantThumbnail
strapiVariantThumbnail,
}, (data) => {
const varData = data.variants.map((variant) => ({
id: variant.id,
@@ -2939,7 +2939,7 @@ export const handleStrapiWebhookWorkflow = createWorkflow(
const variants = updateProductVariantsWorkflow.runAsStep({
input: {
product_variants: [
preparedData.data as unknown as UpsertProductVariantDTO
preparedData.data as unknown as UpsertProductVariantDTO,
],
},
})
@@ -2988,7 +2988,7 @@ export const handleStrapiWebhookWorkflow = createWorkflow(
// Clear the product cache for all affected products
const productIds = transform({ variants }, (data) => {
const uniqueProductIds = [
...new Set(data.variants.map((v) => v.product_id))
...new Set(data.variants.map((v) => v.product_id)),
]
return uniqueProductIds as string[]
})
@@ -3815,7 +3815,7 @@ Then, find the `Text` component wrapping the `{product.description}` and replace
>
<Markdown
allowedElements={[
"p", "ul", "ol", "li", "strong", "em", "blockquote", "hr", "br", "a"
"p", "ul", "ol", "li", "strong", "em", "blockquote", "hr", "br", "a",
]}
unwrapDisallowed
>

View File

@@ -1,22 +1,104 @@
If you are experiencing connection issues when trying to access your Medusa application from a storefront or the admin dashboard, it is most likely due to Cross-Origin Resource Sharing (CORS) issues.
If you're experiencing connection issues when trying to access your Medusa application's API routes from the storefront, admin dashboard, or any client application, it's most likely due to a Cross-Origin Resource Sharing (CORS) error.
You might see a log in your browser console, that looks like this:
To verify it's a CORS error, check your [browser's console](https://developer.mozilla.org/en-US/docs/Learn_web_development/Howto/Tools_and_setup/What_are_browser_developer_tools). You should see an error similar to the following:
![CORS error log](https://res.cloudinary.com/dza7lstvk/image/upload/v1668003322/Medusa%20Docs/Other/jnHK115_udgf2n.png)
```bash
Access to fetch at 'http://localhost:9000/store/products' from origin 'http://localhost:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
```
In your `medusa-config.ts`, ensure that you've configured your CORS settings correctly:
## Why this Error Occurred
This error occurs when you try to access the Medusa server's API routes from a domain that isn't configured in the application's CORS settings. By default, Medusa only allows requests from specific origins to ensure security.
---
## How to Fix It
### Verify Your CORS Settings
Medusa has three CORS settings that you can configure in your `medusa-config.ts` file:
1. [http.storeCors](!docs!/learn/configurations/medusa-config#httpstorecors): Allowed origins for requests to routes starting with `/store`. By default, it's set to `http://localhost:8000` for local development.
2. [http.adminCors](!docs!/learn/configurations/medusa-config#httpadmincors): Allowed origins for requests to routes starting with `/admin`. By default, it's set to `http://localhost:9000` for local development.
3. [http.authCors](!docs!/learn/configurations/medusa-config#httpauthcors): Allowed origins for requests to routes starting with `/auth`. By default, it's set to `http://localhost:8000,http://localhost:9000` for local development.
If your storefront or admin are hosted at different domains or ports, or if you're accessing Medusa's API routes from a different origin (such as an additional storefront), you'll need to update the CORS settings accordingly. You can add additional origins by separating them with commas.
For example, set the following environment variables in your `.env` file or in [Cloud](!cloud!/environments/environment-variables):
```env
STORE_CORS=http://localhost:8000,http://my-custom-store.com
ADMIN_CORS=http://localhost:9000,http://my-custom-admin.com
AUTH_CORS=http://localhost:8000,http://localhost:9000,http://my-custom-store.com,http://my-custom-admin.com
```
Then use the environment variables in your `medusa-config.ts` file:
```ts title="medusa-config.ts"
module.exports = defineConfig({
projectConfig: {
http: {
storeCors: process.env.STORE_CORS || "http://localhost:8000",
adminCors: process.env.ADMIN_CORS || "http://localhost:9000",
authCors: process.env.AUTH_CORS || "http://localhost:8000,http://localhost:9000",
storeCors: process.env.STORE_CORS,
adminCors: process.env.ADMIN_CORS,
authCors: process.env.AUTH_CORS,
},
// ...
},
})
```
Learn more about these configurations in [this documentation](!docs!/learn/configurations/medusa-config#http).
### Apply CORS for Custom Route Prefix
Medusa applies its CORS settings to routes starting with `/store`, `/admin`, and `/auth`. If you've created a route whose path doesn't start with one of these prefixes, you must manually handle CORS for that route.
For example, if you create a custom route at `/custom-routes`, add a middleware to handle CORS for that route:
```ts title="src/api/middlewares.ts"
import { defineMiddlewares } from "@medusajs/framework/http"
import type {
MedusaNextFunction,
MedusaRequest,
MedusaResponse,
} from "@medusajs/framework/http"
import { ConfigModule } from "@medusajs/framework/types"
import { parseCorsOrigins } from "@medusajs/framework/utils"
import cors from "cors"
export default defineMiddlewares({
routes: [
{
matcher: "/custom-routes*",
middlewares: [
(
req: MedusaRequest,
res: MedusaResponse,
next: MedusaNextFunction
) => {
const configModule: ConfigModule =
req.scope.resolve("configModule")
return cors({
origin: parseCorsOrigins(
// Use the appropriate CORS setting for your custom route
configModule.projectConfig.http.storeCors
),
credentials: true,
})(req, res, next)
},
],
},
],
})
```
Make sure to:
- Update the `matcher` property to match your custom route path.
- Pass the appropriate CORS setting for your custom route to `parseCorsOrigins`.
---
## Additional Resources
- [Medusa Configuration Options](!docs!/learn/configurations/medusa-config)
- [CORS for Custom Routes](!docs!/learn/fundamentals/api-routes/cors#cors-in-custom-routes)

View File

@@ -5356,14 +5356,6 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/confirmClaimRequestWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "confirmDraftOrderEditWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/confirmDraftOrderEditWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -5396,6 +5388,14 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/confirmVariantInventoryWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "convertDraftOrderWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/convertDraftOrderWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -6733,6 +6733,22 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/completeOrderWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "computeAdjustmentsForPreviewWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/computeAdjustmentsForPreviewWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "computeDraftOrderAdjustmentsWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/computeDraftOrderAdjustmentsWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -6949,6 +6965,14 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/maybeRefreshShippingMethodsWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "onCarryPromotionsFlagSet",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/onCarryPromotionsFlagSet",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -7277,6 +7301,14 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateOrderChangesWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "updateOrderChangeWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateOrderChangeWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -13687,6 +13719,30 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"autogenerate_as_ref": true,
"sort_sidebar": "alphabetize",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "addDraftOrderItemsWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/addDraftOrderItemsWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "addDraftOrderPromotionWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/addDraftOrderPromotionWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "addDraftOrderShippingMethodsWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/addDraftOrderShippingMethodsWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -13719,6 +13775,22 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/batchPromotionRulesWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "computeAdjustmentsForPreviewWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/computeAdjustmentsForPreviewWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "computeDraftOrderAdjustmentsWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/computeDraftOrderAdjustmentsWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -13783,6 +13855,46 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/deletePromotionsWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "onCarryPromotionsFlagSet",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/onCarryPromotionsFlagSet",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "orderEditAddNewItemWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/orderEditAddNewItemWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "orderEditUpdateItemQuantityWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/orderEditUpdateItemQuantityWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "orderExchangeAddNewItemWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/orderExchangeAddNewItemWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "orderExchangeRequestItemReturnWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/orderExchangeRequestItemReturnWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -13791,6 +13903,46 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/refreshCartItemsWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "removeDraftOrderActionItemWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/removeDraftOrderActionItemWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "removeDraftOrderActionShippingMethodWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/removeDraftOrderActionShippingMethodWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "removeDraftOrderPromotionsWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/removeDraftOrderPromotionsWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "removeDraftOrderShippingMethodWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/removeDraftOrderShippingMethodWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "removeItemOrderEditActionWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/removeItemOrderEditActionWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -13823,6 +13975,46 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateCartWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "updateDraftOrderActionItemWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateDraftOrderActionItemWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "updateDraftOrderActionShippingMethodWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateDraftOrderActionShippingMethodWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "updateDraftOrderItemWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateDraftOrderItemWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "updateDraftOrderShippingMethodWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateDraftOrderShippingMethodWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "updateExchangeAddItemWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateExchangeAddItemWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -13831,6 +14023,30 @@ const generatedgeneratedCommerceModulesSidebarSidebar = {
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateLineItemInCartWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "updateOrderChangeWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateOrderChangeWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "updateOrderEditAddItemWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateOrderEditAddItemWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "ref",
"title": "updateOrderEditItemQuantityWorkflow",
"path": "https://docs.medusajs.com/resources/references/medusa-workflows/updateOrderEditItemQuantityWorkflow",
"children": []
},
{
"loaded": true,
"isPathHref": true,