Skip to content

CORS preflight fails due to case-sensitive header comparison (violates RFC 7230) #649

@bdougie

Description

@bdougie
  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

Describe the bug

CORS preflight requests fail when Access-Control-Allow-Headers uses different casing than what browsers send in Access-Control-Request-Headers. Per RFC 7230, HTTP header names are case-insensitive, but Edge Functions appears to perform case-sensitive comparison.

Browsers convert all headers to lowercase in Access-Control-Request-Headers (per CORS spec), so the server-side comparison must be case-insensitive to comply with RFC 7230.

To Reproduce

  1. Deploy an Edge Function with CORS headers using mixed case:
const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'X-Idempotency-Key'
}

Deno.serve(async (req) => {
  if (req.method === 'OPTIONS') {
    return new Response(null, { headers: corsHeaders })
  }
  return new Response('OK', { headers: corsHeaders })
})
  1. Call the function from a browser with the same header:
fetch('https://xxx.supabase.co/functions/v1/test', {
  method: 'POST',
  headers: { 'X-Idempotency-Key': 'abc123' }
})
  1. Observe CORS error: "Request header field x-idempotency-key is not allowed"

Expected behavior

Preflight should succeed because x-idempotency-key and X-Idempotency-Key are the same header per RFC 7230 Section 3.2: "Each header field consists of a case-insensitive field name..."

System information

  • OS: macOS
  • Browser: Chrome, Firefox, Safari (all exhibit same behavior)
  • Version of supabase-js: 2.x
  • Version of Node.js: 20.x

Additional context

Workaround: Include both cases in allowed headers:

'Access-Control-Allow-Headers': 'x-idempotency-key, X-Idempotency-Key'

References:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions