Adding Bearer Plugin Throws "Can't modify immutable headers." #647

Closed
opened 2026-03-13 07:58:49 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @abegehr on GitHub (Feb 10, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Setup a simple Hono app on Cloudflare workers: https://hono.dev/docs/getting-started/cloudflare-workers
  2. Add better-auth: https://www.better-auth.com/docs/integrations/hono
  3. Add the bearer plugin: https://www.better-auth.com/docs/plugins/bearer
  4. Run with wrangler dev
  5. Requests fail with "Internal Server Error": TypeError: Can't modify immutable headers.

Current vs. Expected behavior

I'd expect the bearer plugin to work with Hono and Cloudflare Workers.

What version of Better Auth are you using?

1.1.16

Provide environment information

- OS: macOS 15.3
- Browser: Safari 18.3

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { bearer } from "better-auth/plugins";

export function initAuth(
  db: DB,
  kv: KVNamespace,
  environment: "development" | "production",
) {
  const auth = betterAuth({
    onAPIError: {
      onError: (err) => console.error(err),
    },
    // db
    database: drizzleAdapter(db, {
      provider: "sqlite",
      usePlural: true
    }),
    // providers
    emailAndPassword: {
      enabled: true,
    },
    // cors
    trustedOrigins: ["http://localhost:5173"],
    // secondaryStorage
    secondaryStorage: {
      get: (k) => kv.get("auth:" + k),
      set: (k, v) => kv.put("auth:" + k, v),
      delete: (k) => kv.delete("auth:" + k),
    },
    // plugins
    plugins: [
      bearer(), // FIXME causes "TypeError: Can't modify immutable headers."
    ],
  });

  return auth;
}

Additional context

Sample call the fails:

curl 'http://localhost:8787/api/auth/get-session' \
-X 'GET' \
-H 'Accept: */*' \
-H 'Authorization: Bearer 123'

I tried to clone the request before passing to the auth handler, however same issue:

app.on(["POST", "GET"], "/api/auth/**", (c) => c.var.auth.handler(c.req.raw.clone()));

Related issues:

  1. https://github.com/better-auth/better-auth/issues/1143#issuecomment-2576509063
  2. https://github.com/better-auth/better-auth/issues/1058
Originally created by @abegehr on GitHub (Feb 10, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Setup a simple Hono app on Cloudflare workers: https://hono.dev/docs/getting-started/cloudflare-workers 2. Add better-auth: https://www.better-auth.com/docs/integrations/hono 3. Add the bearer plugin: https://www.better-auth.com/docs/plugins/bearer 4. Run with `wrangler dev` 5. Requests fail with "Internal Server Error": `TypeError: Can't modify immutable headers.` ### Current vs. Expected behavior I'd expect the bearer plugin to work with Hono and Cloudflare Workers. ### What version of Better Auth are you using? 1.1.16 ### Provide environment information ```bash - OS: macOS 15.3 - Browser: Safari 18.3 ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { bearer } from "better-auth/plugins"; export function initAuth( db: DB, kv: KVNamespace, environment: "development" | "production", ) { const auth = betterAuth({ onAPIError: { onError: (err) => console.error(err), }, // db database: drizzleAdapter(db, { provider: "sqlite", usePlural: true }), // providers emailAndPassword: { enabled: true, }, // cors trustedOrigins: ["http://localhost:5173"], // secondaryStorage secondaryStorage: { get: (k) => kv.get("auth:" + k), set: (k, v) => kv.put("auth:" + k, v), delete: (k) => kv.delete("auth:" + k), }, // plugins plugins: [ bearer(), // FIXME causes "TypeError: Can't modify immutable headers." ], }); return auth; } ``` ### Additional context Sample call the fails: ``` curl 'http://localhost:8787/api/auth/get-session' \ -X 'GET' \ -H 'Accept: */*' \ -H 'Authorization: Bearer 123' ``` I tried to clone the request before passing to the auth handler, however same issue: ```ts app.on(["POST", "GET"], "/api/auth/**", (c) => c.var.auth.handler(c.req.raw.clone())); ``` Related issues: 1. https://github.com/better-auth/better-auth/issues/1143#issuecomment-2576509063 2. https://github.com/better-auth/better-auth/issues/1058
GiteaMirror added the stalebug labels 2026-03-13 07:58:49 -05:00
Author
Owner

@SiNONiMiTY commented on GitHub (Feb 10, 2025):

bump, encountering this issue

@SiNONiMiTY commented on GitHub (Feb 10, 2025): bump, encountering this issue
Author
Owner

@SiNONiMiTY commented on GitHub (Feb 10, 2025):

I was able to resolve this by re-initializing the headers to make it immutable: false

Instead of

await auth.api.signOut({
    headers: ctx.req.raw.headers,
})

Make it like

await auth.api.signOut({
    headers: new Headers(ctx.req.raw.headers),
})
@SiNONiMiTY commented on GitHub (Feb 10, 2025): I was able to resolve this by re-initializing the headers to make it `immutable: false` Instead of ```TS await auth.api.signOut({ headers: ctx.req.raw.headers, }) ``` Make it like ```TS await auth.api.signOut({ headers: new Headers(ctx.req.raw.headers), }) ```
Author
Owner

@enqqi commented on GitHub (Feb 10, 2025):

  • Instead of clone() just pass the raw request.
  • For your secondary storage implement the actual function, I know it should work but I had to actually create async functions for the secondaryStorage to work.
// ...truncated
secondaryStorage: {
      get: async (key) => {
        return await x.env.AuthKV.get(key);
      },

      set: async (key, value, ttl) => {
        const options = ttl ? { expirationTtl: ttl } : undefined;
        await x.env.AuthKV.put(key, value, options);
      },

      delete: async (key) => {
        await x.env.AuthKV.delete(key);
      },
    }
@enqqi commented on GitHub (Feb 10, 2025): - Instead of `clone()` just pass the raw request. - For your secondary storage implement the actual function, I know it should work but I had to actually create async functions for the secondaryStorage to work. ```typescript // ...truncated secondaryStorage: { get: async (key) => { return await x.env.AuthKV.get(key); }, set: async (key, value, ttl) => { const options = ttl ? { expirationTtl: ttl } : undefined; await x.env.AuthKV.put(key, value, options); }, delete: async (key) => { await x.env.AuthKV.delete(key); }, } ```
Author
Owner

@dosubot[bot] commented on GitHub (Jun 14, 2025):

Hi, @abegehr. I'm Dosu, and I'm helping the better-auth team manage their backlog. I'm marking this issue as stale.

Issue Summary:

  • You reported a "TypeError: Can't modify immutable headers" error with the bearer plugin in a Hono app on Cloudflare Workers.
  • SiNONiMiTY resolved the issue by re-initializing headers to make them mutable, suggesting a code change to use a new Headers object.
  • enqqi provided advice on handling secondary storage with async functions using Cloudflare's KV storage.

Next Steps:

  • Please confirm if this issue is still relevant to the latest version of the better-auth repository by commenting here.
  • If no updates are provided, the issue will be automatically closed in 7 days.

Thank you for your understanding and contribution!

@dosubot[bot] commented on GitHub (Jun 14, 2025): Hi, @abegehr. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog. I'm marking this issue as stale. **Issue Summary:** - You reported a "TypeError: Can't modify immutable headers" error with the bearer plugin in a Hono app on Cloudflare Workers. - SiNONiMiTY resolved the issue by re-initializing headers to make them mutable, suggesting a code change to use a new `Headers` object. - enqqi provided advice on handling secondary storage with async functions using Cloudflare's KV storage. **Next Steps:** - Please confirm if this issue is still relevant to the latest version of the better-auth repository by commenting here. - If no updates are provided, the issue will be automatically closed in 7 days. Thank you for your understanding and contribution!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#647