Unable to get account data from a plugin middleware/endpoint in stateless mode #2923

Closed
opened 2026-03-13 10:28:00 -05:00 by GiteaMirror · 2 comments
Owner

Originally created by @Neo-Ciber94 on GitHub (Feb 26, 2026).

Originally assigned to: @bytaesu on GitHub.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Configure better auth in stateless mode

account: {
	storeStateStrategy: 'cookie',
	storeAccountCookie: true
},

Create a plugin, and try access the account data

createAuthMiddleware(ctx => {
            // there is not way to consistently extract the `AccountData` from the ctx
})

context.internalAdapter.findAccountByUserId sometimes returns it and other is null, I suppose because is actually going through the memory storage not the account data cookie.

Current vs. Expected behavior

Current

No way to get the account data, I suspect this should be possible with getAccountCookie but is not expose.

Image

Expected

There is an getAccountCookie or a getAccountFromCtx that extracts and decrypts the account cookie.

What version of Better Auth are you using?

1.4.19

System info

{
  "system": {
    "platform": "win32",
    "arch": "x64",
    "version": "Windows 11 Home",
    "release": "10.0.26200",
    "cpuCount": 8,
    "cpuModel": "Intel(R) Core(TM) i5-8300H CPU @ 2.30GHz",
    "totalMemory": "15.88 GB",
    "freeMemory": "2.39 GB"
  },
  "node": {
    "version": "v24.13.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.6.2"
  },
  "frameworks": [
    {
      "name": "svelte",
      "version": "5.49.2"
    },
    {
      "name": "@sveltejs/kit",
      "version": "2.50.2"
    }
  ],
  "databases": [
    {
      "name": "@libsql/client",
      "version": "0.17.0"
    },
    {
      "name": "drizzle",
      "version": "0.45.1"
    }
  ],
  "betterAuth": {
    "version": "Unknown",
    "config": null,
    "error": "Cannot find module '$app/environment'\nRequire stack:\n- ...\\server\\auth\\googleAuth.ts"
  }
}

A database is listed on the config, because is installed, but is not being use for auth.

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

Backend

Auth config (if applicable)

import { betterAuth } from 'better-auth';
import { sveltekitCookies } from 'better-auth/svelte-kit';
import { env } from '$env/dynamic/private';
import { getRequestEvent } from '$app/server';
import { googleAuthPlugin } from './plugins';

export const auth = betterAuth({
	baseURL: env.ORIGIN,
	secret: env.BETTER_AUTH_SECRET,
	session: {
		cookieCache: {
			enabled: true,
		}
	},
	plugins: [googleAuthPlugin(), sveltekitCookies(getRequestEvent)],

	socialProviders: {
		google: {
			accessType: 'offline',
			prompt: 'select_account consent',
			clientId: process.env.GOOGLE_CLIENT_ID as string,
			clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
			scope: ['https://www.googleapis.com/auth/drive.file']
		}
	}
});

Additional context

No response

Originally created by @Neo-Ciber94 on GitHub (Feb 26, 2026). Originally assigned to: @bytaesu on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce Configure better auth in stateless mode ```ts account: { storeStateStrategy: 'cookie', storeAccountCookie: true }, ``` Create a plugin, and try access the account data ```ts createAuthMiddleware(ctx => { // there is not way to consistently extract the `AccountData` from the ctx }) ``` `context.internalAdapter.findAccountByUserId` sometimes returns it and other is null, I suppose because is actually going through the memory storage not the account data cookie. ### Current vs. Expected behavior ### Current No way to get the account data, I suspect this should be possible with `getAccountCookie` but is not expose. <img width="894" height="187" alt="Image" src="https://github.com/user-attachments/assets/7cafc1c3-08f9-45ff-938b-4a76f20f1344" /> ### Expected There is an `getAccountCookie` or a `getAccountFromCtx` that extracts and decrypts the account cookie. ### What version of Better Auth are you using? 1.4.19 ### System info ```bash { "system": { "platform": "win32", "arch": "x64", "version": "Windows 11 Home", "release": "10.0.26200", "cpuCount": 8, "cpuModel": "Intel(R) Core(TM) i5-8300H CPU @ 2.30GHz", "totalMemory": "15.88 GB", "freeMemory": "2.39 GB" }, "node": { "version": "v24.13.0", "env": "development" }, "packageManager": { "name": "npm", "version": "11.6.2" }, "frameworks": [ { "name": "svelte", "version": "5.49.2" }, { "name": "@sveltejs/kit", "version": "2.50.2" } ], "databases": [ { "name": "@libsql/client", "version": "0.17.0" }, { "name": "drizzle", "version": "0.45.1" } ], "betterAuth": { "version": "Unknown", "config": null, "error": "Cannot find module '$app/environment'\nRequire stack:\n- ...\\server\\auth\\googleAuth.ts" } } ``` A database is listed on the config, because is installed, but is not being use for auth. ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from 'better-auth'; import { sveltekitCookies } from 'better-auth/svelte-kit'; import { env } from '$env/dynamic/private'; import { getRequestEvent } from '$app/server'; import { googleAuthPlugin } from './plugins'; export const auth = betterAuth({ baseURL: env.ORIGIN, secret: env.BETTER_AUTH_SECRET, session: { cookieCache: { enabled: true, } }, plugins: [googleAuthPlugin(), sveltekitCookies(getRequestEvent)], socialProviders: { google: { accessType: 'offline', prompt: 'select_account consent', clientId: process.env.GOOGLE_CLIENT_ID as string, clientSecret: process.env.GOOGLE_CLIENT_SECRET as string, scope: ['https://www.googleapis.com/auth/drive.file'] } } }); ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-03-13 10:28:00 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Feb 26, 2026):

You're correct that getAccountCookie exists internally but isn't exported from better-auth/cookies — only createSessionStore and getChunkedCookie are publicly available.

Why internalAdapter.findAccountByUserId returns null: In stateless mode without a database, the adapter methods will return null because there's no persistent storage. This is expected behavior.

Workaround: You can manually decrypt the account cookie in your middleware:

import { symmetricDecodeJWT } from "better-auth/crypto";

createAuthMiddleware(async (ctx) => {
  // Get the account cookie from request headers
  const cookieHeader = ctx.request?.headers?.get('cookie') ?? '';
  const accountCookie = cookieHeader
    .split(';')
    .find(c => c.trim().startsWith('better-auth.account_data'))
    ?.split('=')[1];
  
  if (accountCookie) {
    const accountData = await symmetricDecodeJWT(
      accountCookie,
      ctx.context.secret,
      'better-auth-account'
    );
    const account = JSON.parse(accountData);
    // account contains: accessToken, refreshToken, providerId, userId, etc.
  }
});

This looks like a valid feature request — exposing getAccountCookie (or a similar helper like getAccountFromCtx) would make stateless mode much more usable from plugin middleware.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Feb 26, 2026): <!-- Answer --> You're correct that `getAccountCookie` [exists internally](https://github.com/better-auth/better-auth/blob/074478e928624ca038a579817b47174ac15ef56a/packages/better-auth/src/cookies/session-store.ts#L309-L328) but [isn't exported from `better-auth/cookies`](https://github.com/better-auth/better-auth/blob/074478e928624ca038a579817b47174ac15ef56a/packages/better-auth/src/cookies/index.ts#L564-L566) — only `createSessionStore` and `getChunkedCookie` are publicly available. **Why `internalAdapter.findAccountByUserId` returns null:** In stateless mode without a database, the adapter methods [will return null because there's no persistent storage](https://github.com/better-auth/better-auth/discussions/5957#discussioncomment-15929413). This is expected behavior. **Workaround:** You can manually decrypt the account cookie in your middleware: ```typescript import { symmetricDecodeJWT } from "better-auth/crypto"; createAuthMiddleware(async (ctx) => { // Get the account cookie from request headers const cookieHeader = ctx.request?.headers?.get('cookie') ?? ''; const accountCookie = cookieHeader .split(';') .find(c => c.trim().startsWith('better-auth.account_data')) ?.split('=')[1]; if (accountCookie) { const accountData = await symmetricDecodeJWT( accountCookie, ctx.context.secret, 'better-auth-account' ); const account = JSON.parse(accountData); // account contains: accessToken, refreshToken, providerId, userId, etc. } }); ``` This looks like a valid feature request — exposing `getAccountCookie` (or a similar helper like `getAccountFromCtx`) would make stateless mode much more usable from plugin middleware. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/5f3ce9d1-56a8-458f-88fc-d4e57a5d4faf?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/5f3ce9d1-56a8-458f-88fc-d4e57a5d4faf?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/5f3ce9d1-56a8-458f-88fc-d4e57a5d4faf?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/5f3ce9d1-56a8-458f-88fc-d4e57a5d4faf?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/5f3ce9d1-56a8-458f-88fc-d4e57a5d4faf?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/5f3ce9d1-56a8-458f-88fc-d4e57a5d4faf?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/5f3ce9d1-56a8-458f-88fc-d4e57a5d4faf?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=You%27re%20correct%20that%20%60getAccountCookie%60%20%5Bexists%20internally%5D%28https%3A//github.com/better-auth/better-auth/blob/074478e928624ca038a579817b47174ac15ef56a/packages/better-auth/src/cookies/session-store.ts%23L309-L328%29%20but%20%5Bisn%27t%20exported%20from%20%60better-auth/cookies%60%5D%28https%3A//github.com/better-auth/better-auth/blob/074478e928624ca038a579817b47174ac15ef56a/packages/better-auth/src/cookies/index.ts%23L564-L566%29%20%E2%80%94%20only%20%60createSessionStore%60%20and%20%60getChunkedCookie%60%20are%20publicly%20available.%0A%0A%2A%2AWhy%20%60internalAdapter.findAccountByUserId%60%20returns%20null%3A%2A%2A%20In%20stateless%20mode%20without%20a%20database%2C%20the%20adapter%20methods%20%5Bwill%20return%20null%20because%20there%27s%20no%20persistent%20storage%5D%28https%3A//github.com/better-auth/better-auth/discussions/5957%23discussioncomment-15929413%29.%20This%20is%20expected%20behavior.%0A%0A%2A%2AWorkaround%3A%2A%2A%20You%20can%20manually%20decrypt%20the%20account%20cookie%20in%20your%20middleware%3A%0A%0A%60%60%60typescript%0Aimport%20%7B%20symmetricDecodeJWT%20%7D%20from%20%22better-auth/crypto%22%3B%0A%0AcreateAuthMiddleware%28async%20%28ctx%29%20%3D%3E%20%7B%0A%20%20//%20Get%20the%20account%20cookie%20from%20request%20headers%0A%20%20const%20cookieHeader%20%3D%20ctx.request%3F.headers%3F.get%28%27cookie%27%29%20%3F%3F%20%27%27%3B%0A%20%20const%20accountCookie%20%3D%20cookieHeader%0A%20%20%20%20.split%28%27%3B%27%29%0A%20%20%20%20.find%28c%20%3D%3E%20c.trim%28%29.startsWith%28%27better-auth.account_data%27%29%29%0A%20%20%20%20%3F.split%28%27%3D%27%29%5B1%5D%3B%0A%20%20%0A%20%20if%20%28accountCookie%29%20%7B%0A%20%20%20%20const%20accountData%20%3D%20await%20symmetricDecodeJWT%28%0A%20%20%20%20%20%20accountCookie%2C%0A%20%20%20%20%20%20ctx.context.secret%2C%0A%20%20%20%20%20%20%27better-auth-account%27%0A%20%20%20%20%29%3B%0A%20%20%20%20const%20account%20%3D%20JSON.parse%28accountData%29%3B%0A%20%20%20%20//%20account%20contains%3A%20accessToken%2C%20refreshToken%2C%20providerId%2C%20userId%2C%20etc.%0A%20%20%7D%0A%7D%29%3B%0A%60%60%60%0A%0AThis%20looks%20like%20a%20valid%20feature%20request%20%E2%80%94%20exposing%20%60getAccountCookie%60%20%28or%20a%20similar%20helper%20like%20%60getAccountFromCtx%60%29%20would%20make%20stateless%20mode%20much%20more%20usable%20from%20plugin%20middleware.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8165)
Author
Owner

@bytaesu commented on GitHub (Feb 26, 2026):

Hi @Neo-Ciber94,

Since getSessionCookie is already available, it would make sense for getAccountCookie to be readable as well 🤔

@bytaesu commented on GitHub (Feb 26, 2026): Hi @Neo-Ciber94, Since `getSessionCookie` is already available, it would make sense for `getAccountCookie` to be readable as well 🤔
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2923