{"record":{"id":"fea827929a8b2fcf","repo":"nextauthjs/next-auth","slug":"oauth-provider-returned-an-error","errorCode":null,"errorMessage":"OAuth Provider returned an error","messagePattern":"OAuth Provider returned an error","errorType":"exception","errorClass":"OAuthCallbackError","httpStatus":null,"severity":"error","filePath":"packages/core/src/lib/actions/callback/oauth/callback.ts","lineNumber":147,"sourceCode":"\n  const state = await checks.state.use(cookies, resCookies, options)\n\n  let codeGrantParams: URLSearchParams\n  try {\n    codeGrantParams = o.validateAuthResponse(\n      as,\n      client,\n      new URLSearchParams(params),\n      provider.checks.includes(\"state\") ? state : o.skipStateCheck\n    )\n  } catch (err) {\n    if (err instanceof o.AuthorizationResponseError) {\n      const cause = {\n        providerId: provider.id,\n        ...Object.fromEntries(err.cause.entries()),\n      }\n      logger.debug(\"OAuthCallbackError\", cause)\n      throw new OAuthCallbackError(\"OAuth Provider returned an error\", cause)\n    }\n    throw err\n  }\n\n  const codeVerifier = await checks.pkce.use(cookies, resCookies, options)\n\n  let redirect_uri = provider.callbackUrl\n  if (!options.isOnRedirectProxy && provider.redirectProxyUrl) {\n    redirect_uri = provider.redirectProxyUrl\n  }\n\n  let codeGrantResponse = await o.authorizationCodeGrantRequest(\n    as,\n    client,\n    clientAuth,\n    codeGrantParams,\n    redirect_uri,\n    codeVerifier ?? \"decoy\",","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/lib/actions/callback/oauth/callback.ts#L129-L165","documentation":"When validating the OAuth redirect response, openid-client may raise AuthorizationResponseError (e.g. the provider redirected back with error=access_denied, a missing/mismatched state, or an invalid code). Auth.js catches it inside handleOAuth and rethrows it as OAuthCallbackError('OAuth Provider returned an error') with the provider id and response error entries as the cause.","triggerScenarios":"The provider redirects to the callback URL with an error parameter (user denied consent, app not approved); the state/PKCE cookie is missing or mismatched (blocked cookies, cross-domain redirect, multiple tabs); the authorization code is invalid, expired, or already redeemed.","commonSituations":"User cancels the consent screen at the provider; NEXTAUTH_URL/auth secret mismatch across environments causing state cookie decryption failures; multiple sign-in tabs overwriting state cookies; mobile in-app browsers stripping cookies; provider app in development mode rejecting unregistered testers.","solutions":["Inspect the OAuthCallbackError cause (entries like error, error_description, state) to read the provider's actual rejection reason","If error=access_denied, the user declined consent — handle it gracefully in the UI, no code change needed","Fix cookie/state issues: ensure NEXTAUTH_URL/AUTH_URL matches the origin, cookies are not blocked, and the auth secret is stable across instances","Re-authorize the app / request provider approval scopes if the provider rejects unregistered redirect URIs or unapproved apps"],"exampleFix":"// before\n// no error handling: user sees raw failure after canceling consent\n// after\ntry {\n  await signIn(\"github\")\n} catch (e) {\n  if (e instanceof OAuthCallbackError) {\n    // e.cause.error === \"access_denied\" etc.\n    showToast(\"Sign-in was canceled or rejected by the provider\")\n  }\n}","handlingStrategy":"try-catch","validationCode":"// before redirecting to the provider, confirm callback URL and cookies are sane\nif (!window.cookiesEnabled) console.warn(\"State cookie may be dropped; sign-in can fail\")","typeGuard":"function isOAuthCallbackError(e: unknown): e is OAuthCallbackError {\n  return e instanceof OAuthCallbackError\n}","tryCatchPattern":"try {\n  await signIn(providerId)\n} catch (e) {\n  if (isOAuthCallbackError(e)) {\n    const { error, error_description } = e.cause ?? {}\n    // access_denied, invalid_state, etc. — surface to user or log\n  }\n}","preventionTips":["Keep NEXTAUTH_URL/AUTH_URL and the auth secret consistent across environments and instances","Avoid multiple concurrent sign-in tabs that overwrite state cookies","Pre-register exact callback URLs with the OAuth provider","Test consent-cancellation flows and surface friendly messages for access_denied"],"tags":["oauth","callback","provider-error","state"],"backgroundTag":"oauth-callback-error","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}