Skip to content

Supabase Auth errorSupabase Auth: bad_oauth_state

bad_oauth_state is the Supabase Auth error code for an OAuth callback whose state value Supabase can’t match to a sign-in it started. The current Auth server returns it with the messages “OAuth state parameter is invalid”, “OAuth state not found or expired” or “OAuth state has expired”.

Short answer

Always start social sign-in with signInWithOAuth so Supabase creates the state. On the page the user lands on, read error_code from the URL and show a Sign in again button for bad_oauth_state. Make sure the provider’s callback URL is the callback of this Supabase project, and that users aren’t sent back to an old callback link.

Rather not fix it yourself? App Fix Ticket starts with a fixed-price diagnosis, then a fixed price for the fix before any fix work.

Why Supabase rejects the state, and the fix

  1. 01

    The sign-in took too long

    Each OAuth state expires; the Auth server never sets the limit below five minutes. A user who stops at the provider’s login or 2FA screen comes back to “OAuth state has expired”. Catch the error and restart sign-in.

    const params = new URLSearchParams(window.location.search);
    if (params.get('error_code') === 'bad_oauth_state') {
      showRetry(() => supabase.auth.signInWithOAuth({
        provider: 'google',
        options: { redirectTo: `${location.origin}/auth/callback` },
      }));
    }
  2. 02

    The app made its own state

    “OAuth state (data echoed back by the OAuth provider to Supabase Auth) is not in the correct format.” Supabase docs, Auth error codes (bad_oauth_state)

    Custom OAuth code that sends the user to Google with its own state value fails, because Supabase only accepts the state ID it created. Let signInWithOAuth build the provider URL.

  3. 03

    The callback belongs to another project

    A staging and a production project share one OAuth client, and the provider sends users to the wrong callback. That project has no record of the state, so it returns “not found or expired”. Use one OAuth client per project, or list each callback URL exactly.

  4. 04

    The error lands on the Site URL

    Also check: when the state fails, Supabase can’t read the redirectTo address saved with it, so users land on the Site URL, or the external redirect URL if one is set. Read the error there too. A missing state returns bad_oauth_callback, and a reused PKCE state returns flow_state_already_used.

Checked against the vendor’s docs on : Supabase docs: Auth error codes; Supabase Auth source: external.go (state checks); Supabase Auth source: configuration.go (flow state expiry); Supabase docs: PKCE flow.

Rather hand it over?

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

“Very responsive, attentive to fixing bugs, and completed the project as needed! Thank you!”
A buyer in the United States, July 2022. Shopify on Fiverr
All 127 Fiverr reviews

Related: Supabase invalid flow state (code verifier) · Supabase OAuth provider disabled · Google OAuth redirect_uri_mismatch · Supabase PGRST200

Questions

More on this error

Is bad_oauth_state a Google or GitHub error?

No. The error comes from Supabase Auth rejecting the state value when the user came back to its callback.

Should the state lifetime be raised?

Rarely. Self-hosted Auth can set a longer flow state expiry, but a retry button fixes the usual case of a slow sign-in.

Can you fix it for me?

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

A different error?

Describe it and get a written quote

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.