Is there a preferred way to periodically refresh the cookie cache?
I have a Tanstack Start app. My only uses of "authClient" right now are sign-in, sign-up, and sign-out. After that, I check the session within server functions and redirect to sign-in if no session is present.
I am also using the cookie cache ("better-auth.session_data") to ensure I'm not hitting the database for auth on every request. However, I noticed that after "session_data" expired the first time, it was never refreshed since I'm never calling the "get-session" endpoint again from the client.
So far this all make sense, but I'm trying to figure out the best way to keep the cookie cache populated. A couple things I've looked at: - I can use React Query to refetch with authClient.getSession() periodically... that'll ensure the cookie cache stays relatively updated (depending on how I refetch there could be some periods with no cookie cache.. I can set the refetch based on the cookie expiration too). - Check somewhere if the cookie is present and fetch if not. - Change my setup to use client-side auth more (in addition to server checks)... the refresh might be "free" in this case since it's checking frequently from the client anyway -- this would be quite a bit more network requests for auth I think. Any other preferred options or something I'm missing? I'm not certain what the best practice is for client-side session checks if things are generally working fine without them now (I'm aware of some potential UX benefits).
I am also using the cookie cache ("better-auth.session_data") to ensure I'm not hitting the database for auth on every request. However, I noticed that after "session_data" expired the first time, it was never refreshed since I'm never calling the "get-session" endpoint again from the client.
So far this all make sense, but I'm trying to figure out the best way to keep the cookie cache populated. A couple things I've looked at: - I can use React Query to refetch with authClient.getSession() periodically... that'll ensure the cookie cache stays relatively updated (depending on how I refetch there could be some periods with no cookie cache.. I can set the refetch based on the cookie expiration too). - Check somewhere if the cookie is present and fetch if not. - Change my setup to use client-side auth more (in addition to server checks)... the refresh might be "free" in this case since it's checking frequently from the client anyway -- this would be quite a bit more network requests for auth I think. Any other preferred options or something I'm missing? I'm not certain what the best practice is for client-side session checks if things are generally working fine without them now (I'm aware of some potential UX benefits).
3 Replies
EDIT: this isn't the latest. See below.
I came up with something that works okay, although I'm still interested in what others might think or if there's a simpler solution.
What I did:
1. In my server function that checks auth I'm already checking headers on essentially every request. I added a check to see if the cookie cache is present ("better-auth.session_data"). If it's not (i.e., it's expired), then I set a cookie (not HTTP Only) called "cache-expired=true".
2. In my logged-in layout, I have one query set up with React Query to call authClient.getSession. This is set to a longer time like 15 minutes, and will redirect to log-in if the session is ever null (expired). Before returning it sets the cookie "cache-expired=false" to reset things.
3. I have a separate React Query that runs every 10 seconds and all it does is check document.cookie to see if "cache-expired=true". If found, it'll invalidate the "session" query, causing it to refetch immediately and set the cookie cache.
This setup will not refetch the session as soon as the cookie cache has expired. However, as soon as the user does pretty much anything in the app we'll set the "cache-expired" cookie and then the client will refresh the cookie cache within 10 seconds.
This seems like a decent setup that minimizes unnecessary get-session calls from the client. If the user isn't actively using the app then the session will only be fetched client-side once every 15 minutes (I might even make this longer), which lets me send them to sign-in if the session expires. However, if they are actively using the app and the cookie cache expires, we'll get it reset within 10 seconds of the user's last action.
I could save some of the extra work if I can get a new value for the cookie cache directly from BetterAuth and set it in the server function. That way rather than setting a "cache-expired" cookie and manually refetching from the client, I'd just refresh the cookie cache on the server as we do with the primary session token. Maybe there's already a way to do this?
UPDATE: Improved further. I looked at the Better Auth code and implemented
setCookieCache
on my server. That removes the extra cookie I was making and the 10 second check on the client. Now, any time I find the cookie cache missing on the server I recreate it and set the cookie in the response. That means the only time I ever hit the database for the session is the first request after the cookie cache expires, which is exactly how I'd like it work.Was looking into this quite a bit! Do you have a code snippet with your latest implementation? I tried to implement it in nextjs solely relying on ‘use cache’ but couldn’t really get it working
Hey, I'm not quite ready to share yet since there are some security implications I'm trying to sort out. I'll come back if I work through those!
I was actually able to vastly simplify my solution when I determined that I can pass my "setCookie" function (from TanStack Start) into the getSession call server-side. The Better Auth code will now use that to update cookies for me.
So now all I do is:
For Next.js setting cookies is a handled differently so I'm not sure if you'll find a way to do this easily. Even if you wrapped the Next.js cookie setting code in a setCookie function that matches the expected signature, I think there may be a problem since cookies are (I think recently) async in Next.js.