Chrome Extension Cors Extension Patterns — Best Practices

5 min read

CORS Handling Patterns in Chrome Extensions

Understanding CORS (Cross-Origin Resource Sharing) in Chrome extensions requires recognizing that different extension contexts have different CORS behaviors.

Context Overview

Background Service Worker

// background.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'fetchData') {
    fetch(request.url)
      .then(response => response.json())
      .then(data => sendResponse({ success: true, data }))
      .catch(error => sendResponse({ success: false, error: error.message }));
    return true; // Keep message channel open for async response
  }
});

Content Scripts (Key Gotcha!)

// content.js - This will FAIL for cross-origin URLs
fetch('https://api.example.com/data') // CORS error!
  .then(res => res.json())
  .catch(err => console.error(err));

Content Script Workaround: Message Background

Relay cross-origin requests through the background script:

// content.js
function fetchViaBackground(url) {
  return new Promise((resolve, reject) => {
    chrome.runtime.sendMessage(
      { action: 'fetchProxy', url },
      response => {
        if (response.success) resolve(response.data);
        else reject(new Error(response.error));
      }
    );
  });
}

// Usage
fetchViaBackground('https://api.example.com/data')
  .then(data => console.log(data));

Extension Origin

The extension has its own origin: chrome-extension://[EXTENSION_ID]

Cookies and Credentials

For cross-origin requests requiring cookies:

// background.js - Using credentials
fetch('https://api.example.com/data', {
  method: 'GET',
  credentials: 'include' // Send cookies with request
});

Requires in manifest.json:

{
  "host_permissions": [
    "https://api.example.com/*"
  ],
  "permissions": [
    "cookies"
  ]
}

CORS Preflight

Common Errors and Solutions

Error Cause Solution
CORS blocked in content script Content scripts follow page’s CORS Relay through background
No permission Missing host_permissions Add required domains to manifest
Opaque response Using no-cors mode Cannot read response body

Restricted Headers

Cannot set these headers programmatically:

Opaque Responses

When using mode: 'no-cors':

Testing CORS in Extensions

  1. DevTools Network Tab: Look for CORS errors in console
  2. Background script test: Direct fetch should work
  3. Content script test: Should fail without relay
  4. Check extension permissions in chrome://extensions

Host Permissions Best Practices

{
  "host_permissions": [
    "https://api.example.com/*",  // Specific domain
    "https://*.trusted-site.com/*"  // Wildcard for subdomains
  ]
}

Cross-Origin Request Patterns

Background Fetch Proxy

// background.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === 'proxyFetch') {
    fetch(message.url, message.options)
      .then(r => r.text())
      .then(text => sendResponse({ success: true, data: text }))
      .catch(err => sendResponse({ success: false, error: err.message }));
    return true;
  }
});
// background.js
async function fetchWithCookies(url, cookieDomain) {
  // Get cookies for domain
  const cookies = await chrome.cookies.get({ url, name: '' });
  
  return fetch(url, {
    credentials: 'include'
  });
}

Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.