Advanced CORS with RegExp Support #

XyPriss provides enterprise-grade CORS (Cross-Origin Resource Sharing) configuration with powerful pattern matching capabilities. Unlike traditional CORS implementations, XyPriss supports regular expressions, mixed arrays, and complex origin validation patterns.

Overview #

The advanced CORS system allows you to define origin patterns using:

  • Regular Expressions: /^https?:\/\/localhost:\d+$/ for localhost with any port
  • Wildcard Strings: "localhost:*", "*.example.com"
  • Exact Matches: "https://production.com"
  • Mixed Arrays: Combine all pattern types in a single configuration

Quick Start #

import { createServer } from "xypriss";

const server = createServer({
  security: {
    cors: {
      origin: [
        // RegExp patterns (powerful and flexible)
        /^localhost:\d+$/, // localhost:3000, localhost:8080, etc.
        /^127\.0\.0\.1:\d+$/, // 127.0.0.1:3000, etc.
        /^::1:\d+$/, // IPv6 localhost
        /\.test\.com$/, // *.test.com

        // String patterns (backward compatibility)
        "localhost:*", // Wildcard pattern
        "*.dev.example.com", // Subdomain wildcard

        // Exact matches
        "https://production.com",
        "https://staging.example.com",
      ],
      credentials: true,
      methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
      allowedHeaders: ["Content-Type", "Authorization"],
    },
  },
});

server.get("/api/data", (req, res) => {
  res.xJson({ message: "CORS configured successfully!" });
});

server.start();

Pattern Types #

Regular Expression Patterns #

Use JavaScript RegExp objects for complex pattern matching:

origin: [
  // Match localhost with any port
  /^https?:\/\/localhost:\d+$/,

  // Match any subdomain of example.com
  /^https?:\/\/.*\.example\.com$/,

  // Match specific IP ranges
  /^https?:\/\/192\.168\.1\.\d+:\d+$/,

  // Match development environments
  /^https?:\/\/.*\.(dev|staging|test)\.company\.com$/,
];

Wildcard String Patterns #

Traditional wildcard patterns for simple matching:

origin: [
  "localhost:*", // Any port on localhost
  "*.example.com", // Any subdomain
  "api.*.service.com", // Complex wildcards
  "192.168.1.*:3000", // IP ranges with ports
];

Exact Match Patterns #

For production environments where you want explicit control:

origin: [
  "https://myapp.com",
  "https://api.myapp.com",
  "https://admin.myapp.com",
];

Mixed Pattern Arrays #

Combine all pattern types for maximum flexibility:

origin: [
  // RegExp for development
  /^localhost:\d+$/,
  /^127\.0\.0\.1:\d+$/,

  // Wildcards for staging
  "*.staging.company.com",

  // Exact matches for production
  "https://production.company.com",
  "https://api.production.company.com",
];

Configuration Options #

interface CORSConfig {
  /** Origin patterns (strings, RegExp, or mixed arrays) */
  origin?: string | string[] | RegExp | RegExp[];

  /** Allow credentials in CORS requests */
  credentials?: boolean;

  /** Allowed HTTP methods */
  methods?: string[];

  /** Allowed headers */
  allowedHeaders?: string[];

  /** Cache duration for preflight requests (in seconds) */
  maxAge?: number;

  /** Expose additional headers to client */
  exposedHeaders?: string[];

  /** Custom success status for OPTIONS requests */
  optionsSuccessStatus?: number;
}

Advanced Examples #

Development Environment #

const server = createServer({
  security: {
    cors: {
      origin: [
        // Local development
        /^localhost:\d+$/,
        /^127\.0\.0\.1:\d+$/,
        /^0\.0\.0\.0:\d+$/,
        /^::1:\d+$/, // IPv6

        // Development domains
        /\.dev\.company\.com$/,
        /\.staging\.company\.com$/,

        // Local testing tools
        /^https?:\/\/localhost:\d+$/,
        "http://localhost:3000",
        "http://localhost:8080",
      ],
      credentials: true,
    },
  },
});

Multi-Environment Configuration #

const corsOrigins =
  process.env.NODE_ENV === "production"
    ? ["https://myapp.com", "https://api.myapp.com"]
    : [
        /^localhost:\d+$/,
        /^127\.0\.0\.1:\d+$/,
        /\.dev\.myapp\.com$/,
        "https://staging.myapp.com",
      ];

const server = createServer({
  security: {
    cors: {
      origin: corsOrigins,
      credentials: true,
    },
  },
});

API Gateway Pattern #

const server = createServer({
  security: {
    cors: {
      origin: [
        // Allow all subdomains of trusted domains
        /^https?:\/\/.*\.trusted-domain\.com$/,

        // Specific API clients
        "https://client1.com",
        "https://client2.com",

        // Development environments
        /^localhost:\d+$/,

        // IP ranges for internal services
        /^https?:\/\/10\.0\.\d+\.\d+:\d+$/,
        /^https?:\/\/192\.168\.\d+\.\d+:\d+$/,
      ],
      credentials: true,
      methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
      allowedHeaders: [
        "Content-Type",
        "Authorization",
        "X-API-Key",
        "X-Request-ID",
      ],
      exposedHeaders: [
        "X-RateLimit-Limit",
        "X-RateLimit-Remaining",
        "X-RateLimit-Reset",
      ],
    },
  },
});

Mobile App Support #

const server = createServer({
  security: {
    cors: {
      origin: [
        // Web origins
        /^https?:\/\/localhost:\d+$/,
        "https://myapp.com",

        // Mobile app origins (custom schemes)
        /^myapp:\/\//,
        /^com\.company\.myapp:\/\//,

        // Capacitor/Cordova origins
        /^http:\/\/localhost:\d+$/, // iOS simulator
        /^https?:\/\/192\.168\.1\.\d+:\d+$/, // Android emulator
        /^https?:\/\/10\.0\.2\.2:\d+$/, // Android emulator alternative
      ],
      credentials: false, // Usually false for mobile apps
      methods: ["GET", "POST", "PUT", "DELETE"],
      allowedHeaders: ["Content-Type", "Authorization"],
    },
  },
});

Route-Specific CORS #

Apply different CORS policies to different routes:

const server = createServer({
  security: {
    cors: {
      // Default CORS for all routes
      origin: "https://myapp.com",
      credentials: true,
    },
    routeConfig: {
      cors: {
        // Stricter CORS for admin routes
        includeRoutes: ["/admin/*"],
        config: {
          origin: [
            "https://admin.myapp.com",
            /^localhost:\d+$/, // Allow localhost for development
          ],
          credentials: true,
        },
      },
    },
  },
});

// Public API with relaxed CORS
server.get("/api/public", (req, res) => {
  res.xJson({ message: "Public API" });
});

// Admin API with strict CORS
server.get("/admin/users", (req, res) => {
  res.xJson({ users: [] });
});

Security Considerations #

1. RegExp Safety #

// ✅ Safe: Specific patterns
origin: [
  /^https?:\/\/localhost:\d+$/, // Specific to localhost
  /^https?:\/\/.*\.trusted\.com$/, // Specific domain
];

// ❌ Dangerous: Overly permissive
origin: [
  /.*/, // Matches everything!
  /^https?:\/\/.*$/, // Any HTTPS site
];

2. Credential Handling #

// ✅ Secure: Credentials only for specific origins
cors: {
  origin: [
    "https://myapp.com",     // Specific trusted origin
    /^localhost:\d+$/        // Development only
  ],
  credentials: true
}

// ❌ Insecure: Credentials for any origin
cors: {
  origin: "*",              // Any origin
  credentials: true         // Allows credentials to any site!
}

3. Header Validation #

// ✅ Restrictive headers
cors: {
  allowedHeaders: ["Content-Type", "Authorization", "X-API-Key"];
}

// ❌ Permissive headers (security risk)
cors: {
  allowedHeaders: ["*"]; // Allows any headers
}

Performance Optimization #

Pattern Pre-compilation #

RegExp patterns are pre-compiled for optimal performance:

// Patterns are compiled once at startup
const patterns = [
  /^localhost:\d+$/, // Compiled RegExp
  "*.example.com", // Converted to RegExp internally
  "exact.com", // Exact string match
];

Early Termination #

The validation stops at the first matching pattern:

// Fast: Checks patterns in order until match found
for (const pattern of patterns) {
  if (matches(pattern, origin)) {
    return true; // Exit early on first match
  }
}

Troubleshooting #

Common Issues #

  1. "Origin not allowed" errors

    // Check your pattern syntax
    origin: [
      /^https?:\/\/localhost:\d+$/, // Missing ^ or $ anchors
      "localhost:*", // Correct wildcard syntax
    ];
    
  2. RegExp not matching

    // Debug with console.log
    const server = createServer({
      security: {
        cors: {
          origin: [
            (origin) => {
              console.log("Checking origin:", origin);
              return /^localhost:\d+$/.test(origin);
            },
          ],
        },
      },
    });
    
  3. Preflight request failures

    // Ensure OPTIONS method is allowed
    cors: {
      methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // Include OPTIONS
      maxAge: 86400  // Cache preflight for 24 hours
    }
    

Debug Mode #

Enable detailed CORS logging:

const server = createServer({
  logging: {
    level: "debug",
    components: {
      security: true,
    },
  },
  security: {
    cors: {
      origin: [/^localhost:\d+$/, "*.example.com"],
    },
  },
});

This will log:

[CORS] Checking origin: http://localhost:3000
[CORS] Pattern /^localhost:\d+$/ matched
[CORS] Access granted

Migration Guide #

From Express CORS #

// Express cors
const cors = require("cors");
app.use(
  cors({
    origin: function (origin, callback) {
      const allowedOrigins = ["http://localhost:3000", "https://example.com"];
      if (!origin || allowedOrigins.includes(origin)) {
        callback(null, true);
      } else {
        callback(new Error("Not allowed by CORS"));
      }
    },
  }),
);

// XyPriss equivalent
const server = createServer({
  security: {
    cors: {
      origin: [
        /^localhost:\d+$/, // More flexible than exact matches
        "https://example.com",
      ],
    },
  },
});

From String Arrays #

// Old approach
cors: {
  origin: ["http://localhost:3000", "http://localhost:8080", "*.example.com"];
}

// New approach with RegExp
cors: {
  origin: [
    /^localhost:\d+$/, // Cleaner than listing every port
    /\.example\.com$/, // More precise than wildcards
  ];
}

Browser Compatibility #

Modern Browsers (✅ Full Support) #

  • Chrome 98+
  • Firefox 97+
  • Safari 15.2+
  • Edge 98+

Legacy Browser Considerations #

// Fallback for older browsers
const server = createServer({
  security: {
    cors: {
      origin:
        process.env.NODE_ENV === "production"
          ? "https://myapp.com" // Exact match for older browsers
          : /^localhost:\d+$/, // RegExp for modern browsers
      credentials: true,
    },
  },
});

Integration Examples #

SPA with API #

// Frontend (React/Vue/Angular)
const API_BASE =
  process.env.NODE_ENV === "production"
    ? "https://api.myapp.com"
    : "http://localhost:3001";

fetch(`${API_BASE}/api/data`, {
  credentials: "include", // Required for CORS with credentials
});

// Backend
const server = createServer({
  security: {
    cors: {
      origin:
        process.env.NODE_ENV === "production"
          ? "https://myapp.com"
          : /^localhost:\d+$/,
      credentials: true,
    },
  },
});

Microservices Architecture #

// API Gateway
const gateway = createServer({
  security: {
    cors: {
      origin: ["https://webapp.com", /^https?:\/\/.*\.internal\.company\.com$/],
      credentials: true,
    },
  },
});

// Individual services (trust API Gateway)
const userService = createServer({
  security: {
    cors: {
      origin: "https://api-gateway.company.com",
      credentials: true,
    },
  },
});

Third-Party Integration #

const server = createServer({
  security: {
    cors: {
      origin: [
        // Your own domains
        "https://myapp.com",
        /^localhost:\d+$/,

        // Third-party services
        "https://api.stripe.com",
        "https://www.paypal.com",

        // Webhook endpoints (if needed)
        /^https?:\/\/.*\.webhook\.service\.com$/,
      ],
      credentials: false, // Usually false for third-party
    },
  },
});

Advanced CORS with RegExp support provides enterprise-grade origin validation while maintaining developer-friendly configuration. The mixed pattern approach allows you to use the right tool for each use case, from simple wildcards to complex regular expressions.