logoPushwant Rai
Home
Experience
Education
Projects
Achievements
Blogs

Elsewhere

GitHub
LinkedIn
hi@pushwantrai.com.np

Theme

Understanding CORS: Part 3 - CORS: Headers, Methods, and Credentials

Aug 28, 2023

#CORS#Web Development#Security#Frontend#Backend

Table of Contents

  • Introduction
  • CORS Headers Deep Dive
  • Working with Credentials
  • Best Practices

Introduction

In Part 1, we covered CORS basics, and in Part 2, we explored Fetch API modes. Now, let's dive into the more advanced aspects of CORS: handling different HTTP methods, custom headers, and managing credentials.

CORS Headers Deep Dive

When working with complex cross-origin requests, understanding how different CORS headers interact becomes crucial. Let's explore each important header in detail.

Access-Control-Allow-Methods

This header is crucial when your API supports multiple HTTP methods. Here's how it works:

app.options("/products", cors({ methods: ['DELETE'], origin: function (origin, callback) { if(allowedOrigins.indexOf(origin) !== -1){ callback(null, origin) } else { callback(null, null); } } }))

If we try a PUT request without the proper method configuration:

Method Not Allowed
Method Not Allowed

After adding the correct method:

// Server code to allow DELETE and PUT method in preflight request app.options("/products", cors({ methods: ['DELETE', 'PUT'],
Successful PUT Request

Access-Control-Allow-Headers

When your requests need custom headers, you need to explicitly allow them:

app.options("/products", cors({ methods: ['DELETE', 'PUT'], allowedHeaders: ['X-Token-Age'], origin: function (origin, callback) { if(allowedOrigins.indexOf(origin) !== -1){ callback(null, origin) } else { callback(null, null); } } }))

Let's try sending multiple custom headers:

fetch(`http://localhost:3004/products`, { method: "PUT", mode: "cors", headers: { "X-Token-Age": "3600", "X-Token-Length": "1800" } })

Without proper configuration, we get an error:

Headers Not Allowed

But with proper configuration it will work properly

app.options("/products", cors({ methods: ['DELETE', 'PUT'], allowedHeaders: ['X-Token-Age', 'X-Token-Length'], ...

Working with Credentials

Understanding Credentials in CORS

The Access-Control-Allow-Credentials header is essential when your application needs to send cookies or authentication headers in cross-origin requests.

fetch(`http://localhost:3004/products`, { method: "PUT", mode: "cors", headers: { "X-Token-Age": "3600"}, credentials: "include" // to send cookies from browser })

Without proper credentials configuration in server, you'll see this error:

Credentials Error

To fix this, configure your server:

app.options("/products", cors({ methods: ['DELETE', 'PUT'], allowedHeaders: ['X-Token-Age'], credentials: true, //----->>>required origin: function (origin, callback) { if(allowedOrigins.indexOf(origin) !== -1){ callback(null, origin) } else { callback(null, null); } } }))

Cookie Behavior in Cross-Origin Requests

When working with cookies across domains, there are important considerations:

  1. Domain Limitations

    // This won't work from example.com document.cookie = "token=wqerbkljasdfhy;domain=stackoverflow.com;"
  2. Subdomain Sharing

    • Cookies can be shared between subdomains of the same root domain
    • Set the domain attribute to your root domain
    • Example: .example.com allows sharing between api.example.com and www.example.com

Cookie Security Attributes

Important cookie attributes for secure applications:

// Set secure cookie res.cookie('sessionId', 'abc123', { domain: '.example.com', secure: true, httpOnly: true, sameSite: 'Strict' });
  1. Secure Attribute

    • Ensures cookies are only sent over HTTPS
    • Essential for production environments
  2. HttpOnly Attribute

    • Prevents JavaScript access to cookies
    • Protects against XSS attacks
  3. SameSite Attribute

    • Controls how cookies behave in cross-site requests
    • Options: Strict, Lax, None

Best Practices

  1. Method Handling

    app.use(cors({ methods: ['GET', 'POST', 'PUT', 'DELETE'], allowedHeaders: ['Content-Type', 'Authorization'], credentials: true, origin: allowedOrigins }));
  2. Security Headers

    • Always use specific origins instead of wildcards
    • Implement proper preflight handling
    • Keep allowed headers list minimal
  3. Cookie Security

    // Production cookie settings app.use(session({ cookie: { secure: true, httpOnly: true, domain: '.example.com', sameSite: 'Strict' } }));

Related Resources

  • MDN CORS Headers
  • Cookie Security Best Practices
  • Express CORS Configuration