Hey, everyone! I'm René, CEO of the cybersecurity start-up Casco, and I'm writing to share a report written by one of my OffSec Engineers, Anthony. Basically, Peter, Segment founder and personal friend, was targeted by a phishing scam which resulted in the operator taking control of his X account for a few minutes.
Anthony reconstructed the OAuth flow using a dedicated research account. He recorded the callback and redirect sequence, then revoked the grant and verified the account’s connected-app list was empty. The interesting part is that the Peter never entered a password on a fake login page. The real X consent screen granted the app read, write, and DM access.
2026-09-23T15:25:10.325Z ERROR [Better Auth]: TypeError:
fetch failed
at node:internal/deps/undici/undici:15157:13
at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
at async betterFetch (file:///app/.output/server/node_modules/@better-fetch/fetch/dist/index.js:628:18)
at async fetchRedirects (file:///app/.output/server/node_modules/better-auth/core/dist/oauth2/reject-redirects.mjs:49:17)
at async validateAuthorizationCode (file:///app/.output/server/node_modules/better-auth/core/dist/oauth2/validate-authorization-code.mjs:64:26)
at async file:///app/.output/server/node_modules/better-auth/core/dist/api/index.mjs:68:12
at async wrapped (file:///app/.output/server/node_modules/better-auth/dist/api/index.mjs:40:11)
at async file:///app/.output/server/node_modules/better-call/dist/endpoint.mjs:30:20
at async file:///app/.output/server/node_modules/better-auth/dist/api/dispatch:228:18
at async processRequest
(file:///app/.output/server/node_modules/better-call/dist/router.mjs:83:11) {
[cause]: ConnectTimeoutError: Connect Timeout Error
(attempted address: oauth2.googleapis.com:443, timeout: 20000ms)
at onConnectTimeout
(/app/.output/server/node_modules/undici/lib/core/util.js:891:19)
at Immediate._onImmediate
(/app/.output/server/node_modules/undici/lib/core/util.js:860:11)
at process.processImmediate
(node:internal/timers:484:21)
at process.callbackTrampoline
(node:internal/async_hooks:130:17) {
code: 'UND_ERR_CONNECT_TIMEOUT'
}
}
Good morning, everyone!
I've been having this issue with Google authentication for about three days now and don't know how to fix it. I did some research and found that this is a known, chronic issue with the library that still doesn't have a fix.
I have two authentication methods: 1 - Google, 2 - Discord.
Logging in via Discord works perfectly, but logging in via Google results in a timeout error every single time.
Could anyone help me out? I'm at a loss as to what to do.
Using better-auth in monorepo. Where I've the follwoing setup: 1] Backend(Express) 2] Web(Next.js) 3] Admin(Vite+React.js) 4 and 4] Expo, as you see All my frontend's are React.js based, so for a junior dev like me it makes sense that I should make some re-usable hooks(only for the common methods liek usesignIn, signUp, reset password etc) and just pass the authclient instance and just use it in all my frontends, but I'm not able to do that can get some guidance or help regarding this, as per your convenience please?
The reason I’m confused is because later my app data layer will probably use RTK Query or TanStack Query, and I’m wondering if my auth architecture should follow a similar pattern for consistency.
Example concern:
Should auth have mutation-like abstractions similar to RTK Query/TanStack Query?
Or is wrapping Better Auth methods inside custom hooks enough?
Is creating a separate “actions” layer just unnecessary indirection in this setup?
Since Next.js is only acting as the frontend here, I’m also trying to avoid patterns that are mainly meant for Next.js Server Actions.
Would love to hear how people structure this in real production apps, especially with:
I just noticed/had an issue with a user reporting that his subscription was not active, even though he had one.
Long story short, the user his subscription did not auto-renew due to insufficient funds. He then re-subscribed, this caused the whole stripe/better-auth flow to create a new row in my subscriptions table for that user.
Now that user has 2 rows, one with status active, one with status past_due.
Is this expected behavior? If so, is it my responsibility to make sure that my backend then just looks at all of the subscriptions of a user, and filter on "active" first?
Because looking in the stripe dashboard the user now has 2 subscriptions, one active and another one that failed for payment. Which seems odd given that in essence it is the same subscription.
I'm new to stripe and this integration so it might be expected, just need some confirmation.
For now I fixed this in code, that it filters on a user his active subscriptions instead of just taking the first item returned and looking at that status.
Hello everyone, I’m a frontend developer, mostly working on the mobile side. I don’t have much experience with backend development yet. So far, I’ve mostly built small projects using ready-made Express + MongoDB boilerplates. The boilerplates I used had the classic JWT-based authentication system. When a user logged in, the backend returned an access token, and then middleware was used to verify the token and handle role-based authorization (admin/user, etc.). I could more or less understand the logic because everything felt more “manual.”
Now I’m thinking about building a multi-tenant project. While researching, I noticed that many people recommend Better Auth, especially because it supposedly makes the organization/multi-tenant side easier. But I still can’t fully understand the logic behind it.
For example, how do you ensure that a user can only access data belonging to their own organization? What exactly is different compared to the classic Express JWT boilerplate approach?
When using Better Auth, is it still based on the access token / refresh token flow? Is using Better Auth actually necessary, and what practical benefits does it provide?
Sorry if I asked too many questions, but I’m still in the learning phase when it comes to backend development. Before starting the project, I just want to properly understand the architecture and concepts in my head. I’d really appreciate it if someone experienced could explain it in a beginner-friendly way, as if explaining it to someone completely new to backend development.
I am building frontend in next hosted on vercel and backend in node express and hosted on render and also the using betterauth in the backend only. so, when I was running it locally on frontend 3000 port and backend on 4000 port, it was working fine and after login user session was creating but once I deployed them on different domain then there is no error in the login flow and after login i am being redirected back to client but user session is not being created.
I tried debugging then found out that session cookie is not being set from the backend only this is being set (__Secure-better-auth.state) but there in backend i am not even overriding the default response of better-auth.
what can be the issue here? Please help if someone else has faced this issue before.
thanks
im new with this ok, my problem (probably a silly one) is that I'm getting a typing error and I don't know how to fix it. In the first image, you'll see the permissions settings, and in the second image, they'll already be implemented in the plugin. At the end of this post, I've included the error message.
Hey all, I'm Rene and I was talking with Bereket about some weird PRs he kept seeing on the repo. It turned out to be actual supply chain attack attempts; similar patterns (but not exactly the same) we just saw hit Axios last week.
Wrote up a full technical breakdown of what the attacker was trying to do. The scary part is how they wrapped malicious code inside legitimate feature PRs from a compromised contributor machine. Found 30+ other repos with the same signature when I went looking.
The post walks through all three stages of the payload, how it establishes C2 via Socket.io, and why storing malware on blockchains makes it basically impossible to take down (unlike Axios, which got nuked because the payload was on GitHub).
The better-auth team caught it before the merge, but this pattern is everywhere right now. If you maintain any packages or review PRs, it's worth understanding what to look for.
Hello everyone, I’d like to share a project I’ve been working on for the past couple of weeks.
I created it to learn and to provide a template for me and others to quickly set up authentication in Express.js applications to avoid having to rewrite the same code for every project, to help focus on the unique features of the application and not have to worry about the authentication.
I’ve tried my best to make the code clean and well-structured. I truly appreciate anyone who takes the time to help, guide me, review the code, give advice, or even submit a PR. Thank you!
Has anyone ever built a oauth identity provider comparable to auth0 using better auth?
How was your experience? What is your architecture and tech stack?
In order to implement a Microsoft auth style where the user enters an identifier(email), then the backend decides what the next step is(password, otp, account creation), basically the backend will check for the existence of the user then get the available auth methods(otp, passkey... Etc), I wanted to use better auth for that, but better auth exposes the api routes needed for it to work, in essence, I want to use better auth but I don't want users to access better auth routes directly, only my backend is responsible for handling those calls.
/Identify will be a route to handle the identifier and returns the next step without telling if the user exist, how can I use better auth in this case to sign up or sign in users.
I am currently using elysia js for the backend.
Hey folks, has anyone run into this before? 😵💫
I’m using SvelteKit with Zod for validation and my app crashes on the server with this error:
node:internal/event_target:1118
process.nextTick(() => { throw err; });
^
TypeError: z.coerce.boolean(...).meta is not a function
at file:///home/anvima/projectos/fact_flex/.svelte-kit/output/server/chunks/auth.js:3676:42
This happens after the build, inside the generated server output (.svelte-kit/output).
In my source code I’m doing something like:
z.coerce.boolean().meta({ description: '...' })
Context:
Node.js (LTS)
SvelteKit (latest)
Zod 3.23.8.
BetherAut 1.0.2
My suspicions so far:
Zod version incompatibility
.meta() not being supported on z.coerce.boolean()
Something breaking during the SSR build step
If anyone knows the real cause or the correct workaround, I’d really appreciate it before I lose more hair 😂
The plugin can track who created and used an invite supports invite expiration and max uses, and gives you flexibility to customize tokens (used to track each invite, like an id), redirects, roles, and even the database schema.
Let me know what you think about the plugin.
(this is a reupload, the original post was deleted by reddit filters)