{"record":{"id":"7c83d0f2946f257d","repo":"decolua/9router","slug":"failed-to-decrypt-zed-access-token-message","errorCode":null,"errorMessage":"Failed to decrypt Zed access token: ${message}","messagePattern":"Failed to decrypt Zed access token: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"open-sse/shared/zedAuth.js","lineNumber":154,"sourceCode":"  const encrypted = Buffer.from(String(encryptedAccessToken), \"base64url\");\n  try {\n    return crypto\n      .privateDecrypt(\n        { key: privateKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: \"sha256\" },\n        encrypted,\n      )\n      .toString(\"utf8\");\n  } catch (oaepError) {\n    try {\n      return crypto\n        .privateDecrypt(\n          { key: privateKey, padding: crypto.constants.RSA_PKCS1_PADDING },\n          encrypted,\n        )\n        .toString(\"utf8\");\n    } catch {\n      const message = oaepError instanceof Error ? oaepError.message : String(oaepError);\n      throw new Error(`Failed to decrypt Zed access token: ${message}`);\n    }\n  }\n}\n\nexport function buildZedUserAuthHeader(credentials) {\n  const psd = credentials?.providerSpecificData || {};\n  const userId = psd.userId || credentials?.userId;\n  const accessToken = credentials?.accessToken || credentials?.apiKey;\n  if (!userId || !accessToken) {\n    throw new Error(\"Zed credential is missing userId or accessToken\");\n  }\n  return `${userId} ${accessToken}`;\n}\n\nfunction getSystemId(credentials) {\n  return String(\n    credentials?.providerSpecificData?.systemId || credentials?.systemId || \"\",\n  );","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/shared/zedAuth.js#L136-L172","documentation":"decryptZedAccessToken tries RSA privateDecrypt with OAEP-SHA256 padding first, then falls back to PKCS#1 v1.5 padding. If both decryptions fail (wrong key, wrong input encoding, corrupted ciphertext), it rethrows as \"Failed to decrypt Zed access token: <underlying message>\". The underlying message (from the OAEP attempt) names the real crypto failure.","triggerScenarios":"Calling decryptZedAccessToken with an encrypted token that doesn't match the stored private key verifier — mismatched keypair, non-base64url token string, truncated/garbled ciphertext, or a token encrypted with different padding/keys by a newer Zed client.","commonSituations":"User re-ran Zed sign-in so a NEW keypair/token pair exists while the dashboard still stores the old privateKeyVerifier; credential row copied between machines; token value URL-encoded (contains %3D) or padded with '=' instead of base64url.","solutions":["Re-run the Zed sign-in flow so userId, encrypted token, and privateKeyVerifier are regenerated together and stored as one set.","Verify the encrypted token is pure base64url (no '=', no '%3D' escapes, no whitespace) before decrypting.","Confirm the privateKeyVerifier belongs to the same sign-in session as the token — never mix values from different attempts.","Read the embedded underlying message: 'bad decrypt'/length errors usually mean key/padding mismatch; base64 errors mean encoding corruption."],"exampleFix":"// before\ndecryptZedAccessToken(cred.tokenFromOldSession, cred.newKeyVerifier); // mismatched pair\n// after\n// store token+verifier atomically from the same sign-in\ndecryptZedAccessToken(cred.encryptedAccessToken, cred.privateKeyVerifier);","handlingStrategy":"try-catch","validationCode":"function isBase64Url(s) {\n  return typeof s === \"string\" && /^[A-Za-z0-9_-]+$/.test(s) && s.length % 4 !== 1;\n}\n// pre-check: isBase64Url(token) && verifier exists && token+verifier from same session\n","typeGuard":"const isDecryptablePair = (cred) => Boolean(cred?.encryptedAccessToken && cred?.privateKeyVerifier) && isBase64Url(cred.encryptedAccessToken);","tryCatchPattern":"let token;\ntry {\n  token = decryptZedAccessToken(encryptedAccessToken, privateKeyVerifier);\n} catch (e) {\n  // log e.message (contains the underlying crypto reason), then re-run Zed sign-in to mint a fresh keypair+token\n}","preventionTips":["Always store encryptedAccessToken and privateKeyVerifier atomically from the same sign-in attempt.","Never copy credentials between machines without both parts.","On decrypt failure, automatically trigger re-auth instead of retrying with the same data."],"tags":["crypto","rsa","decryption","oauth"],"backgroundTag":"decryption-failed","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}