{"record":{"id":"2dc8ebcc88170d83","repo":"gildas-lormeau/SingleFile","slug":"invalid-auth-response","errorCode":"invalid_auth_response","errorMessage":"invalid_auth_response","messagePattern":"invalid_auth_response","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/lib/gdrive/gdrive.js","lineNumber":296,"sourceCode":"\tconst response = await getJSON(httpResponse);\n\tgdrive.accessToken = response.access_token;\n\tgdrive.refreshToken = response.refresh_token;\n\tgdrive.expirationDate = Date.now() + (response.expires_in * 1000);\n\treturn { accessToken: gdrive.accessToken, refreshToken: gdrive.refreshToken, expirationDate: gdrive.expirationDate };\n}\n\nasync function initAuth(gdrive, options, state) {\n\tlet code;\n\tconst authFlow = { state };\n\ttry {\n\t\tif (nativeWebAuthFlowSupported() && !options.forceWebAuthFlow) {\n\t\t\tconst authURL = await browser.identity.launchWebAuthFlow({\n\t\t\t\tinteractive: options.interactive,\n\t\t\t\turl: gdrive.authURL\n\t\t\t});\n\t\t\tconst searchParams = new URLSearchParams(new URL(authURL).search);\n\t\t\tif (searchParams.get(\"state\") != state) {\n\t\t\t\tthrow new Error(\"invalid_auth_response\");\n\t\t\t}\n\t\t\toptions.code = searchParams.get(\"code\");\n\t\t\treturn await authFromCode(gdrive, options);\n\t\t} else if (options.launchWebAuthFlow) {\n\t\t\toptions.extractAuthCode(browser.identity.getRedirectURL(), authFlow)\n\t\t\t\t.then(authCode => code = authCode)\n\t\t\t\t.catch(() => { /* ignored */ });\n\t\t\treturn await options.launchWebAuthFlow({ url: gdrive.authURL }, authFlow);\n\t\t} else {\n\t\t\tthrow new Error(\"auth_not_supported\");\n\t\t}\n\t}\n\tcatch (error) {\n\t\tif (error.message && (error.message == \"code_required\" || error.message.includes(\"access\"))) {\n\t\t\tif (code) {\n\t\t\t\toptions.code = code;\n\t\t\t\treturn await authFromCode(gdrive, options);\n\t\t\t} else {","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/gildas-lormeau/SingleFile/blob/517fb7c5cf2096d89933b747e862d8ecf616a9f9/src/lib/gdrive/gdrive.js#L278-L314","documentation":"After browser.identity.launchWebAuthFlow completes, initAuth verifies the OAuth 'state' query parameter on the redirect URL against the random state it generated. A mismatch means the redirect did not correspond to this auth request, so it throws 'invalid_auth_response' to prevent CSRF / response mix-ups.","triggerScenarios":"The auth flow redirect URL carries a missing or different state parameter — e.g. a tampered/crafted redirect, a cached redirect from a previous flow, or a provider error page redirecting without state.","commonSituations":"Users aborting the Google consent screen and landing on an error redirect; browser restoring an old redirect URL; launching two overlapping auth flows where responses cross; custom authFlow implementations not preserving state.","solutions":["Retry the auth flow, ensuring only one launchWebAuthFlow is running at a time.","Complete the Google consent screen fully rather than canceling or navigating away.","Clear cached auth state/redirect data and start a fresh flow.","If using a custom launchWebAuthFlow, confirm the final redirect URL preserves the state query parameter."],"exampleFix":"// before\nawait gdrive.auth({ interactive: true }); // invalid_auth_response after canceled flow\n// after\ntry {\n  await gdrive.auth({ interactive: true });\n} catch (e) {\n  if (e.message === 'invalid_auth_response') {\n    await new Promise(r => setTimeout(r, 500)); // let stale flows settle\n    await gdrive.auth({ interactive: true });\n  } else throw e;\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await gdrive.auth({ interactive: true });\n} catch (e) {\n  if (e.message === 'invalid_auth_response') {\n    // stale/mismatched state: retry a fresh single flow\n    await gdrive.auth({ interactive: true });\n  } else throw e;\n}","preventionTips":["Run only one launchWebAuthFlow at a time","Ensure users complete the consent screen; detect cancellation separately","Verify any custom auth flow preserves the state query parameter on redirect"],"tags":["gdrive","oauth","csrf","state-mismatch"],"backgroundTag":"oauth-state-mismatch","analyzedSha":"517fb7c5cf2096d89933b747e862d8ecf616a9f9","analyzedAt":"2026-09-01T10:05:25.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}