mirror of
https://github.com/better-auth/better-auth.git
synced 2026-06-02 12:26:43 -05:00
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Bereket Engida <Bekacru@gmail.com>
62 lines
3.0 KiB
Plaintext
62 lines
3.0 KiB
Plaintext
---
|
|
title: State not found
|
|
description: The state parameter was not found in the request.
|
|
---
|
|
|
|
## What is it?
|
|
|
|
During the OAuth callback, Better Auth expects a `state` value to be present on the incoming request.
|
|
This `state` is originally generated when the OAuth flow starts and is sent to the provider. When the
|
|
provider redirects back to your app, it should include the same `state` value in the callback request.
|
|
If the `state` is missing entirely in the callback request (query or body),
|
|
we cannot validate the flow and the request is rejected.
|
|
|
|
This check prevents CSRF and replay attacks by ensuring the callback belongs to the same browser session
|
|
that initiated the flow.
|
|
|
|
## Common Causes
|
|
|
|
* You navigated directly to `/api/auth/callback` without starting an OAuth flow first.
|
|
* A reverse proxy, CDN, or rewrite stripped query or body parameters from the callback request.
|
|
* The OAuth provider was not given a `state` on the authorize request (custom/manual flow overriding parameters).
|
|
* The callback URL registered at the provider does not match your actual callback route, causing an intermediate
|
|
redirect that drops query or body parameters.
|
|
* The callback reached a different route/handler than expected due to framework routing or middleware, and the
|
|
handler is not reading the query or body you think it is.
|
|
* Mobile/WebView or deep-link handoff opened a new context that lost the original query string.
|
|
|
|
## How to resolve
|
|
|
|
### Start the flow via Better Auth APIs
|
|
|
|
Always initiate OAuth through Better Auth so we can generate and send `state` correctly. Avoid manually hitting
|
|
callback endpoints or constructing authorize URLs unless you fully mirror Better Auth's parameters.
|
|
|
|
### Verify the callback URL and method
|
|
|
|
* Ensure the provider's configured callback URL exactly matches your app's `/api/auth/callback` route (including
|
|
protocol and domain).
|
|
* Most providers redirect via GET with query parameters. If you have custom handlers or methods, confirm the
|
|
handler reads the query/body consistent with your provider's redirect.
|
|
|
|
### Check proxies, rewrites, and middleware
|
|
|
|
* Confirm that any reverse proxies (Vercel, Cloudflare, Nginx) and app-level rewrites preserve the full query
|
|
string (including `state`).
|
|
* If you have middleware that redirects or rewrites the callback path, ensure it forwards query & body parameters intact.
|
|
|
|
### Debug locally
|
|
|
|
Use your browser DevTools → Network to inspect the callback request:
|
|
|
|
* Confirm the callback URL includes `?state=...` (or that the request body contains `state` if you expect one).
|
|
* Verify the authorize request was sent earlier from the same session and that a `state` cookie exists prior to
|
|
the redirect back.
|
|
* Log request query/body fields in your callback handler during local debugging to confirm what is actually
|
|
received by the server.
|
|
|
|
### Edge cases to consider
|
|
|
|
* Preview vs production domains can behave differently if extra redirects or rewrites occur.
|
|
* Mobile/WebView environments and deep links can drop or alter query parameters during handoff.
|