Dev server: plugins importing better-auth/api get a second copy of Better Auth's request state, so getOAuthState() is null in a plugin's callback hook
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 52/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- typescript, vite
- Domain
- build-system, devtools
Research direction
Start by tracing how the void_worker environment configures Vite dependency optimization and how Void loads Better Auth at runtime; the report identifies defineRequestState in @better-auth/core as the source of the module-local ref. Reproduce with the described OAuth callback and compare against the better-auth exclusion in vite.config.ts. Done means the callback hook and Void runtime share request state in dev; verify the reported reproduction and relevant tests.
Written by the indexing model from the issue text.
Description
Void 1.5.0, better-auth 1.7.15, vite 8.3.5, @cloudflare/vite-plugin 2.0.0-beta.v.10, sqlite dialect, void dev.
A Better Auth plugin added in auth.ts registers an after hook on /callback/* and calls getOAuthState() from better-auth/api to read serverContext that the same plugin set with addOAuthServerContext() before calling signInSocial. On the dev server the hook gets null, although the state row in the verification table holds the serverContext and ctx.context.newSession is set. The same plugin works with betterAuth() used directly, outside Void.
Cause, as far as we can tell: Better Auth keys request state by a module-local ref (defineRequestState in @better-auth/core creates const ref = Object.freeze({}) per call; only the AsyncLocalStorage is on globalThis). The worker environment's optimizeDeps excludes void, so Void's runtime (which creates the auth instance and runs the callback) and user code importing better-auth/api (pre-bundled by Vite) load different instances of better-auth/dist/api/state/oauth.mjs. The callback's setOAuthState and the plugin's getOAuthState use different refs. Void already works around the same class of duplicate for its own auth ALS (authContext on a Symbol.for key).
Workaround: environments: { void_worker: { optimizeDeps: { exclude: ['better-auth'] } } } in vite.config.ts, after which the hook sees the state. A production build bundles one copy and is not affected.
Expected: user code and Void's runtime share one instance of better-auth on the dev server, for example by pre-bundling better-auth with Void's runtime, or by Void excluding better-auth along with itself.
Repro: a plugin with addOAuthServerContext({ x: 1 }) + signInSocial()(…) in a GET endpoint, and an after hook on /callback/ logging (await getOAuthState())?.serverContext. Run the flow against any OAuth provider (for example oauth2-mock-server through genericOAuth). It logs null under void dev and { x: 1 } with the exclusion above.
- Dominant language
- TypeScript
- Stars
- 627
- Forks
- 66
- Avg merge
- 14h 38m
- Merged PRs (30d)
- 179
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from voidzero-dev/void
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
voidzero-dev/void#677 ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 30/100
voidzero-dev/void#689 ·
Maintainers usually reply within 1 day
-
`VoidActionError.message` ignores the server's message, though the docs show it to usersPossibly taken A pull request linked to this issue is open or already merged. Open
Difficulty 3/5 1-2 days Newbie friendliness 52/100
voidzero-dev/void#680 ·
Maintainers usually reply within 1 day
-
`withValidator({ body })` rejects the multipart bodies that `useForm` and `action()` send for filesOpen
Difficulty 4/5 3-5 days Newbie friendliness 35/100
voidzero-dev/void#679 ·
Maintainers usually reply within 1 day
-
`Link`: mark the link to the current page (`aria-current`, `data-active`)Possibly taken @yangshun claimed this 1 day ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 25/100
voidzero-dev/void#676 · 2 comments · 1 assignee ·
Maintainers usually reply within 1 day
All issues in voidzero-dev/void
Similar issues
-
needs investigation
Difficulty 2/5 1-3 hours Newbie friendliness 60/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
area:visualizer tech-debt
Difficulty 2/5 Under an hour Newbie friendliness 66/100
jmbarzee/temporal-architect#292 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
riverqueue/river#1576 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
colbymchenry/codegraph#3228 ·
Maintainers usually reply within 1 day