Oauth state not found #2552

Closed
opened 2026-03-13 10:02:40 -05:00 by GiteaMirror · 4 comments
Owner

Originally created by @szaib-dev on GitHub (Dec 17, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

main.ts file

import cors from 'cors';
import helmet from 'helmet';
import morgan from 'morgan';
import dotenv from 'dotenv';
import { toNodeHandler } from "better-auth/node"
import { auth } from './lib/auth';
import prisma from './lib/db';

dotenv.config();
const app = express();
const PORT = process.env.PORT || 4000;

// Middlewares
app.use(express.urlencoded({ extended: true }));
app.use(helmet());
app.use(cors({
  origin: "http://localhost:3000",
  credentials: true
}));
app.use(morgan('dev'));

// Auth route
app.all("/api/auth*", toNodeHandler(auth));

app.use(express.json());
// Other routes
app.post('/api/push', async (req: Request, res: Response) => {
  try {
    const result = await prisma.user.create({
      data: {
        email: "mirza@gmail.com",
        name: "mirza",
      }
    })
    res.status(200).json(result)
  } catch (error) {
    console.error(error)
    return res.json({ error: "error comes 502" })
  }
});

app.get("/api/welcome", async (req, res) => {
  const result = await prisma.user.findMany();
  console.log(result)
  return res.json(result)
})

app.listen(PORT, () => {
  console.log(`🚀 Server running on http://localhost:${PORT}, with: ${process.env.GITHUB_CLIENT_SECRET}`);
});```


---

#Auth.ts

```import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import prisma from "./db";
import { config } from "dotenv";
config()

export const auth = betterAuth({
  database: prismaAdapter(prisma, {
    provider: "postgresql",
  }),
  socialProviders: {
    github: {
      clientId: process.env.GITHUB_CLIENT_ID as string,
      clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
    },
  },
});```


# Actual Error:  `GET /api/auth/error?state=state_not_found 200 5.112 ms - -`

<img width="983" height="643" alt="Image" src="https://github.com/user-attachments/assets/3a261860-1261-41c0-9138-0d2252159b26" />

### Current vs. Expected behavior


# Actual Error:  `GET /api/auth/error?state=state_not_found 200 5.112 ms -

### What version of Better Auth are you using?

latest

### System info

```bash
# Actual Error:  `GET /api/auth/error?state=state_not_found 200 5.112 ms -

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

Backend


### Additional context

_No response_
Originally created by @szaib-dev on GitHub (Dec 17, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce ### main.ts file ```import express, { Request, Response } from 'express'; import cors from 'cors'; import helmet from 'helmet'; import morgan from 'morgan'; import dotenv from 'dotenv'; import { toNodeHandler } from "better-auth/node" import { auth } from './lib/auth'; import prisma from './lib/db'; dotenv.config(); const app = express(); const PORT = process.env.PORT || 4000; // Middlewares app.use(express.urlencoded({ extended: true })); app.use(helmet()); app.use(cors({ origin: "http://localhost:3000", credentials: true })); app.use(morgan('dev')); // Auth route app.all("/api/auth*", toNodeHandler(auth)); app.use(express.json()); // Other routes app.post('/api/push', async (req: Request, res: Response) => { try { const result = await prisma.user.create({ data: { email: "mirza@gmail.com", name: "mirza", } }) res.status(200).json(result) } catch (error) { console.error(error) return res.json({ error: "error comes 502" }) } }); app.get("/api/welcome", async (req, res) => { const result = await prisma.user.findMany(); console.log(result) return res.json(result) }) app.listen(PORT, () => { console.log(`🚀 Server running on http://localhost:${PORT}, with: ${process.env.GITHUB_CLIENT_SECRET}`); });``` --- #Auth.ts ```import { betterAuth } from "better-auth"; import { prismaAdapter } from "better-auth/adapters/prisma"; import prisma from "./db"; import { config } from "dotenv"; config() export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: "postgresql", }), socialProviders: { github: { clientId: process.env.GITHUB_CLIENT_ID as string, clientSecret: process.env.GITHUB_CLIENT_SECRET as string, }, }, });``` # Actual Error: `GET /api/auth/error?state=state_not_found 200 5.112 ms - -` <img width="983" height="643" alt="Image" src="https://github.com/user-attachments/assets/3a261860-1261-41c0-9138-0d2252159b26" /> ### Current vs. Expected behavior # Actual Error: `GET /api/auth/error?state=state_not_found 200 5.112 ms - ### What version of Better Auth are you using? latest ### System info ```bash # Actual Error: `GET /api/auth/error?state=state_not_found 200 5.112 ms - ``` ### Which area(s) are affected? (Select all that apply) Backend ``` ### Additional context _No response_
GiteaMirror added the express label 2026-03-13 10:02:40 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Dec 17, 2025):

tag @better-auth-agent if you would like an answer from the Agent

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

@better-auth-agent[bot] commented on GitHub (Dec 17, 2025): tag @better-auth-agent if you would like an answer from the Agent _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

@dosubot[bot] commented on GitHub (Dec 17, 2025):

Hi @szbr1! I'm Dosu and I’m helping the better-auth team.

The "OAuth state not found" error in Better Auth usually means the OAuth callback was received with a state value that doesn't match any stored session or expected value. The most common causes are:

  • The OAuth flow was started by directly linking to the callback endpoint (like /api/auth/callback/github) instead of initiating from a user-facing route (such as a login page). This skips the state/session setup, so the callback can't validate the request. Always start the flow from your frontend, not by linking directly to the callback endpoint. See details
  • The callbackURL used when starting the OAuth flow is set to the callback endpoint itself, causing the endpoint to be hit twice: once with the correct params, then again without them, triggering the error. The callbackURL should be a regular app route (like /dashboard), not the callback endpoint. The OAuth provider's redirect URI should still point to your backend callback endpoint. See explanation
  • Middleware order matters: mount the Better Auth handler before any body parsing middleware (like express.json()). Otherwise, requests can be intercepted or cookies may not be set/read correctly. See integration notes
  • Database schema mismatches (especially in the verifications or account tables) can cause state verification failures. Make sure your schema matches Better Auth's expectations. See migration notes
  • If you're using mobile/Expo, make sure you have the /expo-authorization-proxy endpoint and are using the latest Better Auth and Expo client versions. See mobile notes

Checklist to resolve:

  1. Make sure you start the OAuth flow from a user-facing route, not by linking directly to the callback endpoint.
  2. Set the callbackURL in your frontend to a regular route (e.g., /dashboard), not /api/auth/callback/github.
  3. Mount the Better Auth handler before any body parsing middleware in Express.
  4. Double-check your database schema for the verifications and account tables.
  5. If using mobile/Expo, ensure the proxy endpoint exists and configs are up to date.

If you want to debug further, enable verbose logging and trace the OAuth flow to see where the state is lost or mismatched. Let me know if you need help with a specific step or config!

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 (Dec 17, 2025): <!-- Greeting --> Hi @szbr1! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> The "OAuth state not found" error in Better Auth usually means the OAuth callback was received with a `state` value that doesn't match any stored session or expected value. The most common causes are: - The OAuth flow was started by directly linking to the callback endpoint (like `/api/auth/callback/github`) instead of initiating from a user-facing route (such as a login page). This skips the state/session setup, so the callback can't validate the request. Always start the flow from your frontend, not by linking directly to the callback endpoint. [See details](https://github.com/better-auth/better-auth/issues/4327) - The `callbackURL` used when starting the OAuth flow is set to the callback endpoint itself, causing the endpoint to be hit twice: once with the correct params, then again without them, triggering the error. The `callbackURL` should be a regular app route (like `/dashboard`), not the callback endpoint. The OAuth provider's redirect URI should still point to your backend callback endpoint. [See explanation](https://github.com/better-auth/better-auth/issues/3488) - Middleware order matters: mount the Better Auth handler before any body parsing middleware (like `express.json()`). Otherwise, requests can be intercepted or cookies may not be set/read correctly. [See integration notes](https://github.com/better-auth/better-auth/issues/2975) - Database schema mismatches (especially in the `verifications` or `account` tables) can cause state verification failures. Make sure your schema matches Better Auth's expectations. [See migration notes](https://github.com/better-auth/better-auth/issues/1749) - If you're using mobile/Expo, make sure you have the `/expo-authorization-proxy` endpoint and are using the latest Better Auth and Expo client versions. [See mobile notes](https://github.com/better-auth/better-auth/issues/6207) **Checklist to resolve:** 1. Make sure you start the OAuth flow from a user-facing route, not by linking directly to the callback endpoint. 2. Set the `callbackURL` in your frontend to a regular route (e.g., `/dashboard`), not `/api/auth/callback/github`. 3. Mount the Better Auth handler before any body parsing middleware in Express. 4. Double-check your database schema for the `verifications` and `account` tables. 5. If using mobile/Expo, ensure the proxy endpoint exists and configs are up to date. If you want to debug further, enable verbose logging and trace the OAuth flow to see where the state is lost or mismatched. Let me know if you need help with a specific step or config! <!-- 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/9dc92c80-c0aa-401d-9db2-7a3a7249e525?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/9dc92c80-c0aa-401d-9db2-7a3a7249e525?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/9dc92c80-c0aa-401d-9db2-7a3a7249e525?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/9dc92c80-c0aa-401d-9db2-7a3a7249e525?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/9dc92c80-c0aa-401d-9db2-7a3a7249e525?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/9dc92c80-c0aa-401d-9db2-7a3a7249e525?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/9dc92c80-c0aa-401d-9db2-7a3a7249e525?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=The%20%22OAuth%20state%20not%20found%22%20error%20in%20Better%20Auth%20usually%20means%20the%20OAuth%20callback%20was%20received%20with%20a%20%60state%60%20value%20that%20doesn%27t%20match%20any%20stored%20session%20or%20expected%20value.%20The%20most%20common%20causes%20are%3A%0A%0A-%20The%20OAuth%20flow%20was%20started%20by%20directly%20linking%20to%20the%20callback%20endpoint%20%28like%20%60/api/auth/callback/github%60%29%20instead%20of%20initiating%20from%20a%20user-facing%20route%20%28such%20as%20a%20login%20page%29.%20This%20skips%20the%20state/session%20setup%2C%20so%20the%20callback%20can%27t%20validate%20the%20request.%20Always%20start%20the%20flow%20from%20your%20frontend%2C%20not%20by%20linking%20directly%20to%20the%20callback%20endpoint.%20%5BSee%20details%5D%28https%3A//github.com/better-auth/better-auth/issues/4327%29%0A-%20The%20%60callbackURL%60%20used%20when%20starting%20the%20OAuth%20flow%20is%20set%20to%20the%20callback%20endpoint%20itself%2C%20causing%20the%20endpoint%20to%20be%20hit%20twice%3A%20once%20with%20the%20correct%20params%2C%20then%20again%20without%20them%2C%20triggering%20the%20error.%20The%20%60callbackURL%60%20should%20be%20a%20regular%20app%20route%20%28like%20%60/dashboard%60%29%2C%20not%20the%20callback%20endpoint.%20The%20OAuth%20provider%27s%20redirect%20URI%20should%20still%20point%20to%20your%20backend%20callback%20endpoint.%20%5BSee%20explanation%5D%28https%3A//github.com/better-auth/better-auth/issues/3488%29%0A-%20Middleware%20order%20matters%3A%20mount%20the%20Better%20Auth%20handler%20before%20any%20body%20parsing%20middleware%20%28like%20%60express.json%28%29%60%29.%20Otherwise%2C%20requests%20can%20be%20intercepted%20or%20cookies%20may%20not%20be%20set/read%20correctly.%20%5BSee%20integration%20notes%5D%28https%3A//github.com/better-auth/better-auth/issues/2975%29%0A-%20Database%20schema%20mismatches%20%28especially%20in%20the%20%60verifications%60%20or%20%60account%60%20tables%29%20can%20cause%20state%20verification%20failures.%20Make%20sure%20your%20schema%20matches%20Better%20Auth%27s%20expectations.%20%5BSee%20migration%20notes%5D%28https%3A//github.com/better-auth/better-auth/issues/1749%29%0A-%20If%20you%27re%20using%20mobile/Expo%2C%20make%20sure%20you%20have%20the%20%60/expo-authorization-proxy%60%20endpoint%20and%20are%20using%20the%20latest%20Better%20Auth%20and%20Expo%20client%20versions.%20%5BSee%20mobile%20notes%5D%28https%3A//github.com/better-auth/better-auth/issues/6207%29%0A%0A%2A%2AChecklist%20to%20resolve%3A%2A%2A%0A1.%20Make%20sure%20you%20start%20the%20OAuth%20flow%20from%20a%20user-facing%20route%2C%20not%20by%20linking%20directly%20to%20the%20callback%20endpoint.%0A2.%20Set%20the%20%60callbackURL%60%20in%20your%20frontend%20to%20a%20regular%20route%20%28e.g.%2C%20%60/dashboard%60%29%2C%20not%20%60/api/auth/callback/github%60.%0A3.%20Mount%20the%20Better%20Auth%20handler%20before%20any%20body%20parsing%20middleware%20in%20Express.%0A4.%20Double-check%20your%20database%20schema%20for%20the%20%60verifications%60%20and%20%60account%60%20tables.%0A5.%20If%20using%20mobile/Expo%2C%20ensure%20the%20proxy%20endpoint%20exists%20and%20configs%20are%20up%20to%20date.%0A%0AIf%20you%20want%20to%20debug%20further%2C%20enable%20verbose%20logging%20and%20trace%20the%20OAuth%20flow%20to%20see%20where%20the%20state%20is%20lost%20or%20mismatched.%20Let%20me%20know%20if%20you%20need%20help%20with%20a%20specific%20step%20or%20config%21)&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/6815)
Author
Owner

@FalconiZzare commented on GitHub (Dec 21, 2025):

This is happening due to cookie domain. The cookie is stored using a domain, but the client cannot find it due to being on a different domain or subDomain. You need to enable crossSubDomain cookies and configure it. Most importantly bring client and server under the same domain name (FQDN).

@FalconiZzare commented on GitHub (Dec 21, 2025): This is happening due to cookie domain. The cookie is stored using a domain, but the client cannot find it due to being on a different domain or subDomain. You need to enable crossSubDomain cookies and configure it. Most importantly bring client and server under the same domain name (FQDN).
Author
Owner

@bytaesu commented on GitHub (Jan 9, 2026):

Hello @szbr1,

There is not enough context to properly handle this issue, and it seems that @FalconiZzare has already provided the proper answer(thank you), so I'm closing this issue.

Feel free to reopen this issue or mention me 🙂

@bytaesu commented on GitHub (Jan 9, 2026): Hello @szbr1, There is not enough context to properly handle this issue, and it seems that @FalconiZzare has already provided the proper answer(thank you), so I'm closing this issue. Feel free to reopen this issue or mention me 🙂
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2552