Skip to main content

CORS Plugin

Enables Cross-Origin Resource Sharing (CORS) in your application. Handles preflight requests and sets appropriate CORS headers for both simple and complex requests.

Quick Start

import { Server } from 'balda-js';

const server = new Server({
plugins: {
cors: {
origin: ['http://localhost:3000'],
credentials: true
}
}
});

Configuration

origin

Configure allowed origins:

// Allow all origins (development only)
cors: {
origin: '*'
}

// Allow specific origins
cors: {
origin: ['https://myapp.com', 'https://admin.myapp.com']
}

// Allow origins with regex
cors: {
origin: ['https://myapp.com', /^https:\/\/.*\.myapp\.com$/]
}

// Function-based validation
cors: {
origin: (origin) => {
const allowedOrigins = ['https://myapp.com'];
return allowedOrigins.includes(origin);
}
}

methods

Configure allowed HTTP methods:

// Default
cors: {
methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE']
}

// Custom
cors: {
methods: ['GET', 'POST', 'PUT', 'DELETE']
}

// String format
cors: {
methods: 'GET,POST,PUT,DELETE'
}

allowedHeaders

Configure allowed request headers:

// Specific headers
cors: {
allowedHeaders: ['Content-Type', 'Authorization', 'X-API-Key']
}

// Allow all
cors: {
allowedHeaders: '*'
}

exposedHeaders

Expose response headers to the client:

cors: {
exposedHeaders: ['X-Total-Count', 'X-Page-Count']
}

credentials

Enable credentials (cookies, authorization headers):

cors: {
origin: ['https://myapp.com'], // Required with credentials
credentials: true
}

maxAge

Cache preflight results (in seconds):

cors: {
maxAge: 86400 // 24 hours
}

Complete Configuration

const server = new Server({
plugins: {
cors: {
origin: ['https://myapp.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
allowedHeaders: ['Content-Type', 'Authorization'],
exposedHeaders: ['X-Total-Count'],
credentials: true,
maxAge: 86400,
preflightContinue: false,
optionsSuccessStatus: 204
}
}
});

Route-Level CORS

Apply CORS to specific routes:

import { cors } from 'balda-js';

@controller('/api')
export class ApiController {
@get('/public', {
middleware: [cors({ origin: '*' })]
})
async publicEndpoint(req: Request, res: Response) {
res.json({ message: 'Public endpoint' });
}

@get('/private', {
middleware: [cors({
origin: ['https://myapp.com'],
credentials: true
})]
})
async privateEndpoint(req: Request, res: Response) {
res.json({ message: 'Private endpoint' });
}
}

Environment-Based Configuration

const isProduction = process.env.NODE_ENV === 'production';

const server = new Server({
plugins: {
cors: {
origin: isProduction
? process.env.ALLOWED_ORIGINS?.split(',')
: ['http://localhost:3000'],
credentials: isProduction,
maxAge: isProduction ? 86400 : undefined
}
}
});

Security Considerations

❌ Wildcard with Credentials

This doesn't work - credentials require specific origins:

cors: {
origin: '*',
credentials: true // Error!
}

✅ Specific Origins with Credentials

cors: {
origin: ['https://myapp.com', 'https://admin.myapp.com'],
credentials: true // Works!
}

Production Configuration

cors: {
origin: ['https://myapp.com'], // Specific origins only
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
maxAge: 86400
}

CORS Headers

Request Headers (from browser)

  • Origin - The origin of the request
  • Access-Control-Request-Method - HTTP method for actual request
  • Access-Control-Request-Headers - Headers for actual request

Response Headers (from server)

  • Access-Control-Allow-Origin - Allowed origins
  • Access-Control-Allow-Methods - Allowed HTTP methods
  • Access-Control-Allow-Headers - Allowed headers
  • Access-Control-Expose-Headers - Headers exposed to client
  • Access-Control-Allow-Credentials - Whether credentials allowed
  • Access-Control-Max-Age - Preflight cache duration

Preflight Requests

CORS automatically handles preflight OPTIONS requests:

OPTIONS /api/users
Origin: https://myapp.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization

→ Response:
Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400