[GH-ISSUE #2054] BUG: unexpected behaviour of getSessionCookie #9029

Closed
opened 2026-04-13 04:18:09 -05:00 by GiteaMirror · 10 comments
Owner

Originally created by @rohittiwari-dev on GitHub (Mar 29, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/2054

I come accross this issue when i was triying to use getSessionCookie in edge function where i can not use env variable from server side

i deleted a user from db and was related to session table cascade delete and update

i checked the code of session api it should ultimately delete the tokens and cookies saved but here is the issue

  1. session table has no sessions
    Image

2.using getSessionCookie in next middleware i can not use env auth from auith.ts because i am using t2-env which doesnot works on edge functions and next js stable version has no support for node js as runtime for now atleast.
Image

  1. even if i am using getSessionCookie it should not return any session data according to session api as it deletes cookies on session not found but it is not deleting data i guess not sure how to solve this issue
    Image
    token in the cookies exists

  2. even though the getSessionCookie function is not working as it should be but authClient.useSession or auth.api.getSession is working as wanted then do not return session that is why my trpc session protected procedure returns error
    Image

  3. as soon as i manually delete better auth cookies getSessionCookie returns null and it works as wanted it redirects to login page

here is auth.ts

import { betterAuth, type BetterAuthOptions } from 'better-auth';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { openAPI } from 'better-auth/plugins';

import db, { schema } from '@/db';
import { env } from '@/env';
import { sendEmail } from '@/lib/emails';
import { redis } from '../redis';
import { nextCookies } from 'better-auth/next-js';

// Server Auth
export const authServerApi = betterAuth({
	appName: 'Notespace',
	database: drizzleAdapter(db, {
		provider: 'pg',
		schema: {
			...schema,
			user: schema.UserTable,
			account: schema.ConnectedAuthProvidersTable,
			session: schema.UserAuthSessionTable,
			verification: schema.UserAuthVerificationTable,
		},
	}),
	emailAndPassword: {
		enabled: true,
		autoSignIn: true,
		requireEmailVerification: true,
		sendResetPassword: async ({ user, url }) => {
			await sendEmail({
				to: user.email,
				subject: 'Reset Your Password | Notespace',
				text: `Click the link to verify your email: ${url}`,
			});
		},
	},
	emailVerification: {
		sendOnSignUp: true,
		autoSignInAfterVerification: true,
		sendVerificationEmail: async ({ user, url }) => {
			await sendEmail({
				to: user.email,
				subject: 'Verify your email address | Notespace',
				text: `Click the link to verify your email: ${url}`,
			});
		},
	},
	socialProviders: {
		google: {
			disableImplicitSignUp: true,
			clientId: env.GOOGLE_CLIENT_ID,
			clientSecret: env.GOOGLE_CLIENT_SECRET,
		},
	},
	onAPIError: {
		errorURL: '/sign-in',
	},
	secondaryStorage: {
		get: async (key) => {
			const value = await redis.get(key);
			return value ? value : null;
		},
		set: async (key, value, ttl) => {
			if (ttl) await redis.set(key, value, 'EX', ttl);
			else await redis.set(key, value);
		},
		delete: async (key) => {
			await redis.del(key);
		},
	},
	plugins: [openAPI(), nextCookies()],
} satisfies BetterAuthOptions);

and my trpc protechted procedure

//context
export const createTRPCContext = async (opts: { headers: Headers }) => {
	const session = await authServerApi.api.getSession({
		headers: opts.headers,
	});
	return {
		user: session?.user,
		session: session,
		...opts,
	};
};

//Middleware
import { TRPCError } from '@trpc/server';
import { createMiddleware } from '../trpc';

export const withAuth = createMiddleware(async ({ ctx, next }) => {
	if (!ctx.session) {
		throw new TRPCError({ code: 'UNAUTHORIZED' });
	}

	return next({
		ctx: {
			session: ctx.session,
		},
	});
});

export default withAuth;

Tech stack
os: windows 11
browser: brave
better-auth : latest stable

Originally created by @rohittiwari-dev on GitHub (Mar 29, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/2054 I come accross this issue when i was triying to use getSessionCookie in edge function where i can not use env variable from server side i deleted a user from db and was related to session table cascade delete and update i checked the code of session api it should ultimately delete the tokens and cookies saved but here is the issue 1. session table has no sessions ![Image](https://github.com/user-attachments/assets/58c7d936-a2d6-4084-862f-5de7189fc201) 2.using getSessionCookie in next middleware i can not use env auth from auith.ts because i am using t2-env which doesnot works on edge functions and next js stable version has no support for node js as runtime for now atleast. ![Image](https://github.com/user-attachments/assets/64fbafdc-78b8-42a0-9149-5744d020844c) 3. even if i am using getSessionCookie it should not return any session data according to session api as it deletes cookies on session not found but it is not deleting data i guess not sure how to solve this issue ![Image](https://github.com/user-attachments/assets/1c518329-f318-4d26-bcb2-dd703ba5d284) token in the cookies exists 4. even though the getSessionCookie function is not working as it should be but authClient.useSession or auth.api.getSession is working as wanted then do not return session that is why my trpc session protected procedure returns error ![Image](https://github.com/user-attachments/assets/9b318ddc-a395-49f3-a9a1-42ed0f35bdaf) 5. as soon as i manually delete better auth cookies getSessionCookie returns null and it works as wanted it redirects to login page here is auth.ts ```typescript import { betterAuth, type BetterAuthOptions } from 'better-auth'; import { drizzleAdapter } from 'better-auth/adapters/drizzle'; import { openAPI } from 'better-auth/plugins'; import db, { schema } from '@/db'; import { env } from '@/env'; import { sendEmail } from '@/lib/emails'; import { redis } from '../redis'; import { nextCookies } from 'better-auth/next-js'; // Server Auth export const authServerApi = betterAuth({ appName: 'Notespace', database: drizzleAdapter(db, { provider: 'pg', schema: { ...schema, user: schema.UserTable, account: schema.ConnectedAuthProvidersTable, session: schema.UserAuthSessionTable, verification: schema.UserAuthVerificationTable, }, }), emailAndPassword: { enabled: true, autoSignIn: true, requireEmailVerification: true, sendResetPassword: async ({ user, url }) => { await sendEmail({ to: user.email, subject: 'Reset Your Password | Notespace', text: `Click the link to verify your email: ${url}`, }); }, }, emailVerification: { sendOnSignUp: true, autoSignInAfterVerification: true, sendVerificationEmail: async ({ user, url }) => { await sendEmail({ to: user.email, subject: 'Verify your email address | Notespace', text: `Click the link to verify your email: ${url}`, }); }, }, socialProviders: { google: { disableImplicitSignUp: true, clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, }, }, onAPIError: { errorURL: '/sign-in', }, secondaryStorage: { get: async (key) => { const value = await redis.get(key); return value ? value : null; }, set: async (key, value, ttl) => { if (ttl) await redis.set(key, value, 'EX', ttl); else await redis.set(key, value); }, delete: async (key) => { await redis.del(key); }, }, plugins: [openAPI(), nextCookies()], } satisfies BetterAuthOptions); ``` and my trpc protechted procedure ```typescript //context export const createTRPCContext = async (opts: { headers: Headers }) => { const session = await authServerApi.api.getSession({ headers: opts.headers, }); return { user: session?.user, session: session, ...opts, }; }; //Middleware import { TRPCError } from '@trpc/server'; import { createMiddleware } from '../trpc'; export const withAuth = createMiddleware(async ({ ctx, next }) => { if (!ctx.session) { throw new TRPCError({ code: 'UNAUTHORIZED' }); } return next({ ctx: { session: ctx.session, }, }); }); export default withAuth; ``` Tech stack os: windows 11 browser: brave better-auth : latest stable
GiteaMirror added the locked label 2026-04-13 04:18:09 -05:00
Author
Owner

@rohittiwari-dev commented on GitHub (Mar 29, 2025):

@Bekacru if you could check and help me out if i am doing anything wrong, thanks and it also dont delete redis session/secondary storage session info or user info in this particular case

<!-- gh-comment-id:2764254607 --> @rohittiwari-dev commented on GitHub (Mar 29, 2025): @Bekacru if you could check and help me out if i am doing anything wrong, thanks and it also dont delete redis session/secondary storage session info or user info in this particular case
Author
Owner

@Kinfe123 commented on GitHub (Mar 30, 2025):

Here is the thing it is just because the session or user is deleted directly from the database without using our API, meaning there’s no built-in mechanism like event polling or webhooks to detect the change and invalidate the session cookie. Since getSessionCookie retrieves the token from cookies without verifying it against the database, which looks on the req headers objects to verify. so thats probably the reason as well.

<!-- gh-comment-id:2764501162 --> @Kinfe123 commented on GitHub (Mar 30, 2025): Here is the thing it is just because the session or user is deleted directly from the database without using our API, meaning there’s no built-in mechanism like event polling or webhooks to detect the change and invalidate the session cookie. Since getSessionCookie retrieves the token from cookies without verifying it against the database, which looks on the req headers objects to verify. so thats probably the reason as well.
Author
Owner

@rohittiwari-dev commented on GitHub (Mar 30, 2025):

Here is the thing it is just because the session or user is deleted directly from the database without using our API, meaning there’s no built-in mechanism like event polling or webhooks to detect the change and invalidate the session cookie. Since getSessionCookie retrieves the token from cookies without verifying it against the database, which looks on the req headers objects to verify. so thats probably the reason as well.

Thanks for reply but , the user is deleted from server action i am using drizzle db to delete the user and i did it that way and did not used the api provided because i had to do some operation which is subjected to my requirement and if i use both the apis and my transactional based operation it is something i dont wanted. i was keen to implement raw

In any case i would there should be option to perform this safely because i cam using cascade reference in many places and not made paranoid structure slowly i would move it

useSession and getSession works well but not in middleware because next js 15 it throws error i have no other option other than this and it is unsafe if user is banned or blocked or some manual action take to remove user then also user will be able to login until token expired but data is not available and that can crash the application

@Kinfe123 could you please help me on this

<!-- gh-comment-id:2764514612 --> @rohittiwari-dev commented on GitHub (Mar 30, 2025): > Here is the thing it is just because the session or user is deleted directly from the database without using our API, meaning there’s no built-in mechanism like event polling or webhooks to detect the change and invalidate the session cookie. Since getSessionCookie retrieves the token from cookies without verifying it against the database, which looks on the req headers objects to verify. so thats probably the reason as well. Thanks for reply but , the user is deleted from server action i am using drizzle db to delete the user and i did it that way and did not used the api provided because i had to do some operation which is subjected to my requirement and if i use both the apis and my transactional based operation it is something i dont wanted. i was keen to implement raw In any case i would there should be option to perform this safely because i cam using cascade reference in many places and not made paranoid structure slowly i would move it useSession and getSession works well but not in middleware because next js 15 it throws error i have no other option other than this and it is unsafe if user is banned or blocked or some manual action take to remove user then also user will be able to login until token expired but data is not available and that can crash the application @Kinfe123 could you please help me on this
Author
Owner

@rohittiwari-dev commented on GitHub (Mar 30, 2025):

we can have two option either we can have a seperate function for middleware which edge supported util next js support node js or we can fix this function i guess

<!-- gh-comment-id:2764515890 --> @rohittiwari-dev commented on GitHub (Mar 30, 2025): we can have two option either we can have a seperate function for middleware which edge supported util next js support node js or we can fix this function i guess
Author
Owner

@Kinfe123 commented on GitHub (Mar 30, 2025):

also nodejs is supported as runtime for middleware - https://nextjs.org/docs/app/building-your-application/routing/middleware#runtime or does it has some ties with trpc on updating the nexjts version ?

<!-- gh-comment-id:2764522281 --> @Kinfe123 commented on GitHub (Mar 30, 2025): also nodejs is supported as runtime for middleware - https://nextjs.org/docs/app/building-your-application/routing/middleware#runtime or does it has some ties with trpc on updating the nexjts version ?
Author
Owner

@rohittiwari-dev commented on GitHub (Mar 30, 2025):

@Kinfe123 its canary yet not stable i will have to shift to canary for that which is not suggested for next js which is in continuos development
i have tried it before hand only when i saw it in better auth doc

Image

and yes trpc 11 stable version is released and has no issue with next js 15 and i think its not trpc error

<!-- gh-comment-id:2764547341 --> @rohittiwari-dev commented on GitHub (Mar 30, 2025): @Kinfe123 its canary yet not stable i will have to shift to canary for that which is not suggested for next js which is in continuos development i have tried it before hand only when i saw it in better auth doc ![Image](https://github.com/user-attachments/assets/d4a9e9eb-7de9-4595-9061-21116fb2ef34) and yes trpc 11 stable version is released and has no issue with next js 15 and i think its not trpc error
Author
Owner

@Kinfe123 commented on GitHub (Mar 30, 2025):

i mean the issue is not trpc as i have mentioned but most of the purging here is somehow tied with with the auth layer like calling actions to delete the user using your own orm does not have a relation with us but if you intended to use you have to use the api exposed but i see your usecase might be different , so as i said the issue is some client and server mismatch which you are expriencing so may be try other validation other than based on cookies like calling getSession which entirely lives on ur server as server state with in your RSC's or may be using admin plugin (for banning / unbanning users) as well or create your own plugin that can fit your requirements which is easy and well documented.

<!-- gh-comment-id:2764567152 --> @Kinfe123 commented on GitHub (Mar 30, 2025): i mean the issue is not trpc as i have mentioned but most of the purging here is somehow tied with with the auth layer like calling actions to delete the user using your own orm does not have a relation with us but if you intended to use you have to use the api exposed but i see your usecase might be different , so as i said the issue is some client and server mismatch which you are expriencing so may be try other validation other than based on cookies like calling getSession which entirely lives on ur server as server state with in your RSC's or may be using admin plugin (for banning / unbanning users) as well or create your [own plugin](https://www.better-auth.com/docs/concepts/plugins#creating-a-plugin) that can fit your requirements which is easy and well documented.
Author
Owner

@rohittiwari-dev commented on GitHub (Mar 30, 2025):

@Kinfe123 in any of your suggested case either i have to use your api else auth server api or plugin created by me i will have to use auth.api..... so on in middleware which is not yet supported, what i liked about better-auth was simplicity like clerk i have very simple use case anyways if there can be any fix to this issue it will be really great @Bekacru

<!-- gh-comment-id:2764572743 --> @rohittiwari-dev commented on GitHub (Mar 30, 2025): @Kinfe123 in any of your suggested case either i have to use your api else auth server api or plugin created by me i will have to use auth.api..... so on in middleware which is not yet supported, what i liked about better-auth was simplicity like clerk i have very simple use case anyways if there can be any fix to this issue it will be really great @Bekacru
Author
Owner

@Kinfe123 commented on GitHub (Mar 30, 2025):

If the middleware is a thing that is causing the issue , that's why I suggested to run the functions on RSC's , otherwise I will try to run of t3 check for repro if possible.

<!-- gh-comment-id:2764574852 --> @Kinfe123 commented on GitHub (Mar 30, 2025): If the middleware is a thing that is causing the issue , that's why I suggested to run the functions on RSC's , otherwise I will try to run of t3 check for repro if possible.
Author
Owner

@dosubot[bot] commented on GitHub (Jul 2, 2025):

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

Issue Summary:

  • The getSessionCookie function does not delete session data as expected in edge function environments.
  • Persistent tokens remain in cookies even when the session table is empty.
  • The issue arises when users are deleted directly from the database without using the API.
  • @Kinfe123 suggests server-side validation or plugins to detect changes and invalidate session cookies.
  • You are seeking a simple solution compatible with middleware, which is currently not fully supported.

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!

<!-- gh-comment-id:3028421707 --> @dosubot[bot] commented on GitHub (Jul 2, 2025): Hi, @rohittiwari-dev. 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:** - The `getSessionCookie` function does not delete session data as expected in edge function environments. - Persistent tokens remain in cookies even when the session table is empty. - The issue arises when users are deleted directly from the database without using the API. - @Kinfe123 suggests server-side validation or plugins to detect changes and invalidate session cookies. - You are seeking a simple solution compatible with middleware, which is currently not fully supported. **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#9029