How It Works Features Pricing Blog
Log In Start Free Trial
Express · JavaScript

Fix CORS Error: Access-Control-Allow-Origin header missing in Express

This error occurs when a browser blocks a cross-origin request because the server response lacks the Access-Control-Allow-Origin header. Fix it by installing and configuring the cors middleware in your Express app, specifying allowed origins, methods, and headers for your frontend domain.

Reading the Stack Trace

Access to XMLHttpRequest at 'http://localhost:4000/api/users' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. GET http://localhost:4000/api/users net::ERR_FAILED 200 Uncaught (in promise) AxiosError {message: 'Network Error', name: 'AxiosError', code: 'ERR_NETWORK', config: {...}, request: XMLHttpRequest} at XMLHttpRequest.handleError (node_modules/axios/lib/adapters/xhr.js:162:14) at XMLHttpRequest.dispatchEvent (node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:26:19) at XMLHttpRequest.send (node_modules/jsdom/lib/jsdom/living/xmlhttprequest/XMLHttpRequest-impl.js:553:15) at dispatchXhrRequest (node_modules/axios/lib/adapters/xhr.js:52:13) at new Promise (<anonymous>) at xhrAdapter (node_modules/axios/lib/adapters/xhr.js:15:10)

Here's what each line means:

Common Causes

1. No CORS middleware configured

The Express server does not include any CORS middleware, so cross-origin requests from the frontend are blocked by the browser.

const express = require('express');
const app = express();

app.get('/api/users', (req, res) => {
  res.json([{ id: 1, name: 'Alice' }]);
});

app.listen(4000);

2. CORS middleware placed after routes

The cors middleware is added after the routes, so it never runs for those routes.

const express = require('express');
const cors = require('cors');
const app = express();

app.get('/api/users', (req, res) => {
  res.json([{ id: 1, name: 'Alice' }]);
});

app.use(cors()); // Too late - routes already defined above

The Fix

Install the cors package and add it as middleware before your routes. Configure it with the specific origin of your frontend to allow cross-origin requests while keeping the API secure.

Before (broken)
const express = require('express');
const app = express();

app.get('/api/users', (req, res) => {
  res.json([{ id: 1, name: 'Alice' }]);
});

app.listen(4000);
After (fixed)
const express = require('express');
const cors = require('cors');
const app = express();

app.use(cors({
  origin: 'http://localhost:3000',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

app.get('/api/users', (req, res) => {
  res.json([{ id: 1, name: 'Alice' }]);
});

app.listen(4000);

Testing the Fix

const request = require('supertest');
const express = require('express');
const cors = require('cors');

describe('CORS configuration', () => {
  let app;

  beforeEach(() => {
    app = express();
    app.use(cors({
      origin: 'http://localhost:3000',
      methods: ['GET', 'POST', 'PUT', 'DELETE'],
      allowedHeaders: ['Content-Type', 'Authorization']
    }));
    app.get('/api/users', (req, res) => {
      res.json([{ id: 1, name: 'Alice' }]);
    });
  });

  it('includes Access-Control-Allow-Origin header', async () => {
    const response = await request(app)
      .get('/api/users')
      .set('Origin', 'http://localhost:3000');
    expect(response.headers['access-control-allow-origin']).toBe('http://localhost:3000');
  });

  it('responds to preflight OPTIONS request', async () => {
    const response = await request(app)
      .options('/api/users')
      .set('Origin', 'http://localhost:3000')
      .set('Access-Control-Request-Method', 'POST');
    expect(response.status).toBe(204);
  });
});

Run your tests:

npm test

Pushing Through CI/CD

git checkout -b fix/cors-configuration,git add src/app.js src/__tests__/cors.test.js package.json,git commit -m "fix: add CORS middleware for cross-origin API access",git push origin fix/cors-configuration

Your CI config should look something like this:

name: CI
on:
  pull_request:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm test
      - run: npm run lint

The Full Manual Process: 18 Steps

Here's every step you just went through to fix this one bug:

  1. Notice the error alert or see it in your monitoring tool
  2. Open the error dashboard and read the stack trace
  3. Identify the file and line number from the stack trace
  4. Open your IDE and navigate to the file
  5. Read the surrounding code to understand context
  6. Reproduce the error locally
  7. Identify the root cause
  8. Write the fix
  9. Run the test suite locally
  10. Fix any failing tests
  11. Write new tests covering the edge case
  12. Run the full test suite again
  13. Create a new git branch
  14. Commit and push your changes
  15. Open a pull request
  16. Wait for code review
  17. Merge and deploy to production
  18. Monitor production to confirm the error is resolved

Total time: 30-60 minutes. For one bug.

Or Let bugstack Fix It in Under 2 minutes

Every step above? bugstack does it automatically.

Step 1: Install the SDK

npm install bugstack-sdk

Step 2: Initialize

const { initBugStack } = require('bugstack-sdk')

initBugStack({ apiKey: process.env.BUGSTACK_API_KEY })

Step 3: There is no step 3.

bugstack handles everything from here:

  1. Captures the stack trace and request context
  2. Pulls the relevant source files from your GitHub repo
  3. Analyzes the error and understands the code context
  4. Generates a minimal, verified fix
  5. Runs your existing test suite
  6. Pushes through your CI/CD pipeline
  7. Deploys to production (or opens a PR for review)

Time from error to fix deployed: Under 2 minutes.

Human involvement: zero.

Try bugstack Free →

No credit card. 5-minute setup. Cancel anytime.

Deploying the Fix (Manual Path)

  1. Install the cors package with npm install cors.
  2. Open a pull request with the CORS middleware configuration.
  3. Wait for CI checks to pass on the PR.
  4. Have a teammate review the allowed origins to ensure they match your deployment domains.
  5. Merge to main and verify cross-origin requests work in staging.

Frequently Asked Questions

BugStack tests CORS headers for both simple and preflight requests, confirms the allowed origin matches your frontend, and verifies no security policies are weakened.

BugStack delivers fixes as pull requests. Your team reviews the CORS configuration to ensure only intended origins are allowed before merging.

No. Using a wildcard allows any website to call your API. Always specify exact origins in production to prevent unauthorized cross-origin access.

CORS is enforced by browsers only. Server-to-server requests (like from Postman or curl) skip CORS entirely, which is why the API works from those tools.