{"record":{"id":"3a86dcdadd6e9b81","repo":"decolua/9router","slug":"desc-windsurf-auth-failed-err-desc","errorCode":null,"errorMessage":"desc ? `Windsurf auth failed: ${err} (${desc})` : `Windsurf auth failed: ${err}`","messagePattern":"desc \\? `Windsurf auth failed: (.+?) \\((.+?)\\)` : `Windsurf auth failed: (.+?)`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/lib/oauth/providers/windsurf.js","lineNumber":38,"sourceCode":"  if (!res.ok) throw new Error(`Windsurf ${path} HTTP ${res.status}: ${text.slice(0, 200)}`);\n  try { return JSON.parse(text); } catch { throw new Error(`Windsurf ${path} invalid JSON`); }\n}\n\n// Parse Windsurf callback (query string or full URL): ?access_token=...&state=...\nfunction parseWindsurfCallback(raw, expectedState) {\n  const text = String(raw || \"\").trim();\n  let queryStr = text;\n  if (text.includes(\"?\")) queryStr = text.slice(text.indexOf(\"?\") + 1);\n  if (text.startsWith(\"#\")) queryStr = text.slice(1);\n  const params = Object.fromEntries(new URLSearchParams(queryStr));\n  const pick = (keys) => {\n    for (const k of keys) { const v = params[k]; if (v && String(v).trim()) return String(v).trim(); }\n    return null;\n  };\n  const err = pick([\"error\"]);\n  if (err) {\n    const desc = pick([\"error_description\"]);\n    throw new Error(desc ? `Windsurf auth failed: ${err} (${desc})` : `Windsurf auth failed: ${err}`);\n  }\n  const accessToken = pick([\"access_token\", \"token\"]);\n  if (!accessToken) throw new Error(\"Windsurf callback missing access_token\");\n  const state = pick([\"state\"]);\n  if (expectedState && state && state !== expectedState) {\n    throw new Error(\"Windsurf callback state mismatch\");\n  }\n  return { firebaseIdToken: accessToken };\n}\n\n// POST RegisterUser {firebase_id_token} → {apiKey, apiServerUrl, name}\nasync function fetchWindsurfRegisterUser(firebaseIdToken) {\n  const data = await windsurfSeatRequest(WINDSURF_CONFIG.registerApiBaseUrl, WINDSURF_CONFIG.registerPath, {\n    firebase_id_token: firebaseIdToken,\n  });\n  const apiKey = extractJsonPath(data, [[\"apiKey\"], [\"api_key\"]]);\n  if (!apiKey) throw new Error(\"Windsurf RegisterUser missing apiKey\");\n  const apiServerUrl = extractJsonPath(data, [[\"apiServerUrl\"], [\"api_server_url\"]]) || WINDSURF_CONFIG.defaultApiServerUrl;","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/oauth/providers/windsurf.js#L20-L56","documentation":"parseWindsurfCallback inspects the OAuth callback query string and throws this when the provider redirected back with error/error_description parameters instead of a token. The message carries both the OAuth error code and the human-readable description. It means Windsurf's signin refused the login before any token was issued.","triggerScenarios":"User cancels the Windsurf signin page; login fails server-side (access_denied); the firebase auth step inside windsurf.com errors and the redirect carries ?error=...; a malformed auth URL makes the provider respond with an error redirect.","commonSituations":"User closes/aborts the consent screen; Windsurf account has no valid subscription/seat; misconfigured client_id makes Windsurf reject the app; stale cached signin session.","solutions":["Read err and desc from the message — they state exactly why Windsurf refused (e.g. access_denied)","Ask the user to retry the sign-in and complete the Windsurf login/consent screen","Verify client_id and redirect_uri in WINDSURF_CONFIG match the registered Windsurf app","Check the Windsurf account actually has an active seat/subscription","Clear browser cookies for windsurf.com if a stale session causes the error"],"exampleFix":"// before\nconst { firebaseIdToken } = parseWindsurfCallback(callbackUrl, state);\n// after\nlet fb;\ntry { ({ firebaseIdToken: fb } = parseWindsurfCallback(callbackUrl, state)); }\ncatch (e) {\n  if (e.message.startsWith('Windsurf auth failed')) throw new Error('Sign-in was rejected by Windsurf: ' + e.message + ' — please retry and complete the login');\n  throw e;\n}","handlingStrategy":"validation","validationCode":"// inspect the callback BEFORE parsing so you can show a friendly message\nconst params = new URLSearchParams(raw.slice(raw.indexOf('?') + 1));\nif (params.get('error')) {\n  throw new Error(`Sign-in rejected by Windsurf: ${params.get('error')} — ${params.get('error_description') || 'retry and complete login'}`);\n}","typeGuard":"const isAuthRejection = (raw) => /([?&#])error=/.test(String(raw));","tryCatchPattern":"try { const { firebaseIdToken } = parseWindsurfCallback(raw, state); }\ncatch (e) {\n  if (e.message.startsWith('Windsurf auth failed')) {\n    return promptReconnect('Windsurf sign-in was not completed: ' + e.message);\n  }\n  throw e;\n}","preventionTips":["Always complete the Windsurf consent screen; cancelling produces ?error= redirects","Keep client_id/redirect_uri in WINDSURF_CONFIG matching the registered app","Never retry automatically on error callbacks — require user re-authentication","Surface error_description to the user verbatim; it names the exact cause"],"tags":["oauth","oauth-error-callback","windsurf","user-cancelled"],"backgroundTag":"oauth-error-callback","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}