Skip to content

Cookie header not available in mounted handlers without explicit access in onRequest #1618

@pivotdude

Description

@pivotdude

What version of Elysia is running?

1.4.18

What platform is your computer?

Linux 6.12.61-1-MANJARO x86_64 unknown

What environment are you using

bun@1.3.3

Are you using dynamic mode?

no

What steps can reproduce the bug?

  1. Create an Elysia instance with a prefix
  2. Mount an external handler that relies on cookie headers (e.g., better-auth)
  3. Send a request with Cookie header
  4. The mounted handler receives undefined cookie header

Code example:

import { betterAuth } from 'better-auth';
import { openAPI } from 'better-auth/plugins';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { db } from '@/db';
import * as models from '@/models';
import { config } from '@/config';
import { getCorsOrigin } from '@/utils/getCorsOrigin';

const adapter = drizzleAdapter(db, {
  provider: 'pg',
  schema: {
    user: models.user,
    account: models.account,
    session: models.session,
    verificationToken: models.verification,
  },
});

export const auth = betterAuth({
  database: adapter,
  secret: config.AUTH_SECRET,
  origin: config.AUTH_ORIGIN, // http://localhost:5173
  emailAndPassword: {
    enabled: true,
  },
  plugins: [openAPI()],
  trustedOrigins: getCorsOrigin(), // ['http://localhost:5173']
  advanced: {
    useSecureCookies: false,
    defaultCookieAttributes: {
      sameSite: 'lax' as const,
      secure: false,
      httpOnly: true,
      partitioned: false,
    },
  },
  session: {
    cookieCache: {
      enabled: true,
      maxAge: 5 * 60,
    },
  },
});
import Elysia from 'elysia';
import { auth } from './auth.config'; // better-auth instance

// This DOESN'T work - cookie header is undefined
const app = new Elysia({ prefix: '/auth' })
  .mount(auth.handler)
  .listen(3000);

// Test with: 
// curl -H "Cookie: session_token=abc123" http://localhost:3000/auth/get-session
// Result: Cookie header is undefined in auth.handler

What is the expected behavior?

Mounted handlers should receive properly parsed request headers, including the cookie header, without requiring any workarounds.

When sending a request with Cookie: session=xyz header, the mounted handler should be able to access headers.cookie and receive the value "session=xyz".

This should work the same way as regular route handlers defined with .get(), .post(), etc.

What do you see instead?

The cookie header is undefined in mounted handlers unless explicitly accessed in an onRequest hook before mounting.

Different scenarios:

No onRequest hook:

.mount(auth.handler) // headers.cookie = undefined

Empty onRequest hook:

.onRequest(() => {})
.mount(auth.handler) // headers.cookie = undefined

Accessing headers.cookie in onRequest:

.onRequest(({ headers }) => {
  void headers.cookie; // Forces parsing
})
.mount(auth.handler) // headers.cookie = "session=xyz"

Using console.log (forces synchronization):

.onRequest(({ headers }) => {
  console.log(headers.cookie);
})
.mount(auth.handler) // headers.cookie = "session=xyz"

This behavior suggests a race condition or lazy initialization where headers are not parsed/available until explicitly accessed.

Additional information

Current workaround:

.onRequest(({ headers }) => {
  // WORKAROUND: Force headers parsing before mounting
  const _ = request.headers.get('cookie');
})
.mount(handler)

Impact:
This breaks authentication flows when using:

  • better-auth
  • lucia-auth
  • Any handler expecting cookies for session management

Additional observations:

  • Issue only occurs with .mount(), not with regular .get(), .post() handlers
  • Issue occurs regardless of whether the mounted handler is from an external library or locally defined
  • Both console.log() and explicit headers.cookie access fix the issue
  • Empty hooks (() => {}) do NOT fix the issue
  • Suggests the problem is in how Elysia handles context passing between hooks and mounted handlers

Related code:
The issue appears to be in the middleware chain initialization when using .mount(). Headers might be lazily evaluated and not properly passed to mounted handlers until accessed.

Have you try removing the node_modules and bun.lockb and try again yet?

no

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions