Skip to content

@clerk/chrome-extension blocks email/password login due to Origin vs Authorization header conflict (Edge Network Security Rule) #170

Description

@andypetrella

@clerk/chrome-extension blocks email/password login due to Origin vs Authorization header conflict (Edge Network Security Rule)

Context & Environment

  • Package: @clerk/chrome-extension (v2.7.3+) / @clerk/clerk-js (v5.125.0)
  • Browser: Google Chrome / Chromium (v120+)
  • Environment: Chrome Extension MV3 Popup / Standalone Page
  • Reproduction: 100% reproducible on the official clerk-chrome-extension-demo repository when testing out-of-the-box in production config (without syncHost or when syncHost is blocked by third-party cookie restrictions).

Summary

When using the <SignIn /> component inside a Chrome Extension popup (or testing the official Plasmo demo), submitting the user's email address results in an immediate 400 rejection from the Clerk API.

The Clerk Edge Network returns the following error message inside the SignIn component UI:

"For security purposes, only one of the 'Origin' and 'Authorization' headers should be provided, but not both. In browser contexts, the 'Origin' header is set automatically by the browser. In native application contexts (e.g. mobile apps), set the 'Authorization' header."

Root Cause Analysis

  1. When @clerk/chrome-extension initializes, it passes _is_native=1 to the Clerk API, thereby instructing the frontend SDK to behave as a native application and attach the Authorization: Bearer <publishable_key> header to network requests.
  2. However, because the component is rendered inside a Chrome Extension Popup, the rendering environment is inherently a web browser (chrome-extension://...).
  3. Google Chrome natively forces the Origin header (Origin: chrome-extension://<extension-id>) onto outgoing fetch requests. This cannot be prevented by JavaScript using standard fetch APIs.
  4. The Clerk Backend API receives BOTH the Origin header (from Chrome) and the Authorization header (from the Clerk SDK).
  5. Clerk's edge router immediately blocks the request because it sees conflicting contexts (Browser Origin vs Native Auth), even if the extension ID is properly whitelisted in allowed_origins in the dashboard!

Steps to Reproduce

  1. Clone the official demo: git clone https://github.com/clerk/clerk-chrome-extension-demo.git
  2. Configure .env.production with your live publishable key (PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY) and live frontend API (CLERK_FRONTEND_API). Do not set/rely on syncHost since Third-Party Sandbox blocking neutralizes it for many users anyway.
  3. Build the extension: pnpm run build
  4. Load the unpacked extension into Chrome.
  5. In the Clerk Dashboard, whitelist your generated chrome-extension://... URL in "Allowed Redirect URIs" and "CORS Allowed Origins".
  6. Open the newly built Demo popup and enter an email address to sign in.
  7. Click "Continue".
  8. Result: The component flashes red with the Origin vs Authorization conflict error.

The Temporary Workaround (For Users)

To bypass this architectural conflict in production apps without modifying Clerk's code, developers are currently forced to use Chrome's declarativeNetRequest API to manually strip the Origin header before it reaches Clerk:

manifest.json:

"permissions": ["declarativeNetRequest"],
"declarative_net_request": {
  "rule_resources": [{
    "id": "clerk_rules",
    "enabled": true,
    "path": "clerk_rules.json"
  }]
}

clerk_rules.json:

[
  {
    "id": 1,
    "priority": 1,
    "action": {
      "type": "modifyHeaders",
      "requestHeaders": [{ "header": "Origin", "operation": "remove" }]
    },
    "condition": {
      "urlFilter": "||clerk.xxx.com/*",
      "resourceTypes": ["xmlhttprequest"]
    }
  }
]

By stripping Chrome's native Origin header, the Clerk backend only sees the Authorization header and correctly resolves the request as "Native", bypassing the conflict.

Expected Behavior

@clerk/chrome-extension should intelligently recognize that it is operating within a Chrome extension where the Origin header is immutable, and coordinate with the Edge Network to permit Authorization: Bearer requests originating from whitelisted chrome-extension:// origins, rather than rejecting them outright. Or, the SDK should defer entirely to cookies/CORS when the origin is known.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions