{"record":{"id":"a62b7a0c3397aa2c","repo":"xtekky/gpt4free","slug":"missing-pkce-verifier-in-state-parameter","errorCode":null,"errorMessage":"Missing PKCE verifier in state parameter","messagePattern":"Missing PKCE verifier in state parameter","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"g4f/Provider/needs_auth/Antigravity.py","lineNumber":623,"sourceCode":"        code: str,\n        state: str,\n    ) -> Dict[str, Any]:\n        \"\"\"\n        Exchange authorization code for access and refresh tokens.\n\n        Args:\n            code: Authorization code from OAuth callback\n            state: State parameter containing PKCE verifier\n\n        Returns:\n            Dict containing tokens and user info\n        \"\"\"\n        decoded_state = decode_oauth_state(state)\n        verifier = decoded_state.get(\"verifier\", \"\")\n        project_id = decoded_state.get(\"projectId\", \"\")\n\n        if not verifier:\n            raise RuntimeError(\"Missing PKCE verifier in state parameter\")\n\n        start_time = time.time()\n\n        # Exchange code for tokens\n        async with aiohttp.ClientSession() as session:\n            token_data = {\n                \"client_id\": cls.OAUTH_CLIENT_ID,\n                \"client_secret\": cls.OAUTH_CLIENT_SECRET,\n                \"code\": code,\n                \"grant_type\": \"authorization_code\",\n                \"redirect_uri\": ANTIGRAVITY_REDIRECT_URI,\n                \"code_verifier\": verifier,\n            }\n\n            async with session.post(\n                \"https://oauth2.googleapis.com/token\",\n                data=token_data,\n                headers={","sourceCodeStart":605,"sourceCodeEnd":641,"githubUrl":"https://github.com/xtekky/gpt4free/blob/973504e1770928ed5fb82f43da528f441ad9ddc3/g4f/Provider/needs_auth/Antigravity.py#L605-L641","documentation":"During OAuth code exchange, the state parameter is base64-decoded and must contain a 'verifier' field (the PKCE code_verifier generated when the authorization URL was built). This error means the state passed to exchange_code_for_tokens has no verifier — usually because a hand-built or altered state string was used instead of the one returned by build_authorization_url.","triggerScenarios":"exchange_code_for_tokens(code, state) where decode_oauth_state(state) yields no 'verifier' key. Happens when the caller fabricates the state, truncates the redirect URL when pasting it in manual mode, or uses a state from a different/older authorization session.","commonSituations":"User pastes only part of the redirect URL in the manual login flow; the authorization URL was built by an old provider version with a different state schema; custom login scripts that pass their own state parameter.","solutions":["Always generate the authorization URL via cls.build_authorization_url() and use the state it returns, unchanged, in the exchange.","In manual paste mode, paste the FULL redirect URL (including the complete state query parameter), not just the code.","Restart the login flow from scratch so a fresh state/verifier pair is created.","Upgrade g4f so the state encoding used to build and decode matches."],"exampleFix":"# before: hand-rolled state breaks PKCE\nstate = \"mypayload\"  # no verifier -> RuntimeError\n\n# after: use the provider's own PKCE URL builder\nauth_url, state, verifier = Antigravity.build_authorization_url()\n# ... after redirect, pass the callback's state back verbatim:\ntokens = await Antigravity.exchange_code_for_tokens(code, callback_state)","handlingStrategy":"validation","validationCode":"from g4f.Provider.needs_auth.Antigravity import decode_oauth_state\n\ndef state_has_verifier(state: str) -> bool:\n    try:\n        return bool(decode_oauth_state(state).get(\"verifier\"))\n    except Exception:\n        return False\n\n# before exchange:\nassert state_has_verifier(callback_state), \"state lost its PKCE verifier; restart login\"","typeGuard":"def is_valid_pkce_state(state: str) -> bool:\n    \"\"\"True when the OAuth state decodes and carries a PKCE verifier.\"\"\"\n    try:\n        decoded = decode_oauth_state(state)\n    except Exception:\n        return False\n    return isinstance(decoded, dict) and bool(decoded.get(\"verifier\"))","tryCatchPattern":"try:\n    tokens = await Antigravity.exchange_code_for_tokens(code, state)\nexcept RuntimeError as e:\n    if \"Missing PKCE verifier\" in str(e):\n        auth_url, state, _ = Antigravity.build_authorization_url()  # restart flow\n        raise","preventionTips":["Never construct the state parameter yourself; always use build_authorization_url's return value","Pass the callback's state through unmodified — do not substitute a hardcoded one","In manual mode, paste the full redirect URL so state arrives intact"],"tags":["oauth","pkce","antigravity","state"],"backgroundTag":null,"analyzedSha":"973504e1770928ed5fb82f43da528f441ad9ddc3","analyzedAt":"2026-08-14T23:45:32.408Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}