[GH-ISSUE #6520] [Bug] auth.api.getSession() returns wrapped { response: Response } instead of session data #27860

Closed
opened 2026-04-17 19:06:30 -05:00 by GiteaMirror · 9 comments
Owner

Originally created by @N0SAFE on GitHub (Dec 4, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6520

Environment

  • Better Auth version: 1.4.5 (also verified behavior in 1.4.6-beta.2 source)
  • Framework: NestJS with ORPC
  • Node version: 20.x

Description

When calling auth.api.getSession() from server-side code, the function returns a wrapped object { response: Response } instead of the expected { session, user } data, even when not using asResponse: true.

Expected Behavior

const result = await auth.api.getSession({ headers });
// Expected: { session: {...}, user: {...} } or null

Actual Behavior

const result = await auth.api.getSession({ headers });
// Actual: { response: Response } where Response is a web Response object
// Need to do: JSON.parse(await result.response.text()) to get actual data

Root Cause Found

Looking at the source code in to-auth-endpoints.ts (lines ~94-97), I found that returnHeaders and returnStatus are hardcoded to true internally:

internalContext.asResponse = false;
internalContext.returnHeaders = true;  // Always true
internalContext.returnStatus = true;   // Always true

This causes the response to always be wrapped as { headers, response, status } regardless of what the caller expects.

Reproduction

Using Better Auth with ORPC in NestJS, extracting session in a middleware/plugin:

// ORPC Plugin to inject session into context
const authPlugin = new StandardHandlerPlugin({
  rootInterceptors: [
    async (input, context, meta, next) => {
      const headers = context.request?.headers;
      
      // This returns { response: Response } instead of { session, user }
      const result = await auth.api.getSession({
        headers: new Headers(Object.entries(headers || {})),
      });
      
      // WORKAROUND: Have to manually extract the session
      if (result && 'response' in result && result.response instanceof Response) {
        const body = await result.response.text();
        const parsed = JSON.parse(body);
        context.session = parsed.session;
        context.user = parsed.user;
      }
      
      return next({ input, context, meta });
    },
  ],
});

Current Workaround

Helper to handle the wrapped response:

async function extractSession(result: unknown): Promise<{ session: Session; user: User } | null> {
  if (!result) return null;
  
  // Handle the { response: Response } wrapper
  if (typeof result === 'object' && 'response' in result) {
    const wrapped = result as { response: Response };
    if (wrapped.response instanceof Response) {
      const text = await wrapped.response.text();
      if (!text) return null;
      return JSON.parse(text);
    }
  }
  
  // Direct session data (expected behavior)
  if ('session' in (result as object)) {
    return result as { session: Session; user: User };
  }
  
  return null;
}

Questions

  1. Is this intentional behavior? If so, what's the recommended way to get session data server-side?
  2. Is there a configuration option to disable the response wrapping?
  3. Will there be a fix to respect the caller's intent (return raw data when asResponse is not set)?

Thank you for the great library!

Originally created by @N0SAFE on GitHub (Dec 4, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6520 ## Environment - **Better Auth version**: 1.4.5 (also verified behavior in 1.4.6-beta.2 source) - **Framework**: NestJS with ORPC - **Node version**: 20.x ## Description When calling `auth.api.getSession()` from server-side code, the function returns a wrapped object `{ response: Response }` instead of the expected `{ session, user }` data, even when **not** using `asResponse: true`. ## Expected Behavior ```typescript const result = await auth.api.getSession({ headers }); // Expected: { session: {...}, user: {...} } or null ``` ## Actual Behavior ```typescript const result = await auth.api.getSession({ headers }); // Actual: { response: Response } where Response is a web Response object // Need to do: JSON.parse(await result.response.text()) to get actual data ``` ## Root Cause Found Looking at the source code in `to-auth-endpoints.ts` (lines ~94-97), I found that `returnHeaders` and `returnStatus` are **hardcoded to `true`** internally: ```typescript internalContext.asResponse = false; internalContext.returnHeaders = true; // Always true internalContext.returnStatus = true; // Always true ``` This causes the response to always be wrapped as `{ headers, response, status }` regardless of what the caller expects. ## Reproduction Using Better Auth with ORPC in NestJS, extracting session in a middleware/plugin: ```typescript // ORPC Plugin to inject session into context const authPlugin = new StandardHandlerPlugin({ rootInterceptors: [ async (input, context, meta, next) => { const headers = context.request?.headers; // This returns { response: Response } instead of { session, user } const result = await auth.api.getSession({ headers: new Headers(Object.entries(headers || {})), }); // WORKAROUND: Have to manually extract the session if (result && 'response' in result && result.response instanceof Response) { const body = await result.response.text(); const parsed = JSON.parse(body); context.session = parsed.session; context.user = parsed.user; } return next({ input, context, meta }); }, ], }); ``` ## Current Workaround Helper to handle the wrapped response: ```typescript async function extractSession(result: unknown): Promise<{ session: Session; user: User } | null> { if (!result) return null; // Handle the { response: Response } wrapper if (typeof result === 'object' && 'response' in result) { const wrapped = result as { response: Response }; if (wrapped.response instanceof Response) { const text = await wrapped.response.text(); if (!text) return null; return JSON.parse(text); } } // Direct session data (expected behavior) if ('session' in (result as object)) { return result as { session: Session; user: User }; } return null; } ``` ## Questions 1. Is this intentional behavior? If so, what's the recommended way to get session data server-side? 2. Is there a configuration option to disable the response wrapping? 3. Will there be a fix to respect the caller's intent (return raw data when `asResponse` is not set)? Thank you for the great library!
GiteaMirror added the lockedbug labels 2026-04-17 19:06:30 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Dec 4, 2025):

tag @better-auth-agent if you would like an answer from the Agent

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3611031003 --> @better-auth-agent[bot] commented on GitHub (Dec 4, 2025): tag @better-auth-agent if you would like an answer from the Agent _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@better-auth-agent[bot] commented on GitHub (Dec 4, 2025):

Hi there! It looks like you’re experiencing an issue where getSession is always returning a wrapped { response } object even when asResponse isn’t set—which isn’t the intended behavior. In prior issues related to getSession, the expected behavior has been to return plain session data unless explicitly requested otherwise. This appears to be due to the internal configuration (where returnHeaders and returnStatus are forced to true) that unintentionally overrides the caller’s intent.

In the meantime, your workaround to parse result.response is valid—as a temporary fix, manually extracting and parsing the response data will let you obtain the session and user details. We’re investigating a fix to ensure that when asResponse isn’t set, getSession returns the raw session data as expected.

Could you let us know if you’re using any additional custom configurations on your server? Tag @bekacru and @ping__ if you’d like further assistance on this from the Better Auth team. Tag @better-auth-agent if you would like an answer from the Agent.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3611038652 --> @better-auth-agent[bot] commented on GitHub (Dec 4, 2025): Hi there! It looks like you’re experiencing an issue where getSession is always returning a wrapped { response } object even when asResponse isn’t set—which isn’t the intended behavior. In prior issues related to getSession, the expected behavior has been to return plain session data unless explicitly requested otherwise. This appears to be due to the internal configuration (where returnHeaders and returnStatus are forced to true) that unintentionally overrides the caller’s intent. In the meantime, your workaround to parse result.response is valid—as a temporary fix, manually extracting and parsing the response data will let you obtain the session and user details. We’re investigating a fix to ensure that when asResponse isn’t set, getSession returns the raw session data as expected. Could you let us know if you’re using any additional custom configurations on your server? Tag @bekacru and @ping__ if you’d like further assistance on this from the Better Auth team. Tag @better-auth-agent if you would like an answer from the Agent. <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@N0SAFE commented on GitHub (Dec 4, 2025):

no additional setup only a nestjs server with better auth and orpc on the last version

<!-- gh-comment-id:3611041844 --> @N0SAFE commented on GitHub (Dec 4, 2025): no additional setup only a nestjs server with better auth and orpc on the last version
Author
Owner

@jonathansamines commented on GitHub (Dec 4, 2025):

Hey @N0SAFE any chance you can share your complete auth instance config? This is not reproducible with the shared snippet alone, so we'd need a bit more help to triage this issue.

<!-- gh-comment-id:3613418495 --> @jonathansamines commented on GitHub (Dec 4, 2025): Hey @N0SAFE any chance you can share your complete auth instance config? This is not reproducible with the shared snippet alone, so we'd need a bit more help to triage this issue.
Author
Owner

@N0SAFE commented on GitHub (Dec 4, 2025):

yes i can give you the full repository if you want to dive in it
its https://github.com/N0SAFE/nextjs-nestjs-turborepo-template under the apps/api/src/core/modules/auth/services/auth.service.ts#createOrpcAuthMiddleware

<!-- gh-comment-id:3614236124 --> @N0SAFE commented on GitHub (Dec 4, 2025): yes i can give you the full repository if you want to dive in it its https://github.com/N0SAFE/nextjs-nestjs-turborepo-template under the apps/api/src/core/modules/auth/services/auth.service.ts#createOrpcAuthMiddleware
Author
Owner

@jonathansamines commented on GitHub (Dec 4, 2025):

yes i can give you the full repository if you want to dive in it its https://github.com/N0SAFE/nextjs-nestjs-turborepo-template under the apps/api/src/core/modules/auth/services/auth.service.ts#createOrpcAuthMiddleware

Any particular branch? Couldn't find your provided reference on main.

<!-- gh-comment-id:3614289840 --> @jonathansamines commented on GitHub (Dec 4, 2025): > yes i can give you the full repository if you want to dive in it its https://github.com/N0SAFE/nextjs-nestjs-turborepo-template under the apps/api/src/core/modules/auth/services/auth.service.ts#createOrpcAuthMiddleware Any particular branch? Couldn't find your provided reference on main.
Author
Owner

@N0SAFE commented on GitHub (Dec 9, 2025):

@jonathansamines yes at this url e2e8f7875b/apps/api/src/core/modules/auth/services/auth.service.ts (L61)

<!-- gh-comment-id:3633081945 --> @N0SAFE commented on GitHub (Dec 9, 2025): @jonathansamines yes at this url https://github.com/N0SAFE/nextjs-nestjs-turborepo-template/blob/e2e8f7875b5bc822999f6cb740b571aafc762377/apps/api/src/core/modules/auth/services/auth.service.ts#L61
Author
Owner

@jonathansamines commented on GitHub (Dec 9, 2025):

@jonathansamines yes at this url e2e8f7875b/apps/api/src/core/modules/auth/services/auth.service.ts (L61)

Just pulled the latest of main and can now see the reference, but still cannot reproduce your issue. Any particular steps/tasks we can run to see the issue? Tried with bun run check but not seeing the error you are describing.

<!-- gh-comment-id:3633485839 --> @jonathansamines commented on GitHub (Dec 9, 2025): > [@jonathansamines](https://github.com/jonathansamines) yes at this url https://github.com/N0SAFE/nextjs-nestjs-turborepo-template/blob/e2e8f7875b5bc822999f6cb740b571aafc762377/apps/api/src/core/modules/auth/services/auth.service.ts#L61 Just pulled the latest of main and can now see the reference, but still cannot reproduce your issue. Any particular steps/tasks we can run to see the issue? Tried with `bun run check` but not seeing the error you are describing.
Author
Owner

@N0SAFE commented on GitHub (Dec 11, 2025):

i am really sorry i have link you the wrong file... thats the file https://github.com/N0SAFE/nextjs-nestjs-turborepo-template/blob/main/apps/api/src/core/modules/auth/orpc/plugins/auth.plugin.ts but it seems to have been fixed in the last version of better-auth so thanks you

<!-- gh-comment-id:3641082568 --> @N0SAFE commented on GitHub (Dec 11, 2025): i am really sorry i have link you the wrong file... thats the file https://github.com/N0SAFE/nextjs-nestjs-turborepo-template/blob/main/apps/api/src/core/modules/auth/orpc/plugins/auth.plugin.ts but it seems to have been fixed in the last version of better-auth so thanks you
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#27860