decolua/9router · error · Error

Zed callback must include user_id and access_token

Error message

Zed callback must include user_id and access_token

What it means

After parsing the Zed callback payload (JSON or URL query), parseZedCallbackPayload requires both a user id (`user_id`/`userId`) and an encrypted access token (`access_token`/`accessToken`/`token`). If either key is missing or empty it throws this error, because a Zed credential cannot be constructed without both values.

Source

Thrown at open-sse/shared/zedAuth.js:128

    let url;
    try {
      url = new URL(raw);
    } catch {
      try {
        url = new URL(`http://127.0.0.1/?${raw.replace(/^\?/, "")}`);
      } catch {
        throw new Error("Invalid Zed callback URL");
      }
    }
    url.searchParams.forEach((value, key) => {
      data[key] = value;
    });
  }

  const userId = data.user_id || data.userId;
  const encryptedAccessToken = data.access_token || data.accessToken || data.token;
  if (!userId || !encryptedAccessToken) {
    throw new Error("Zed callback must include user_id and access_token");
  }
  return { userId: String(userId), encryptedAccessToken: String(encryptedAccessToken) };
}

/** Decrypt the RSA-encrypted access token using the stored private key. */
export function decryptZedAccessToken(encryptedAccessToken, privateKeyVerifier) {
  const privateKey = decodeZedPrivateKeyVerifier(privateKeyVerifier);
  const encrypted = Buffer.from(String(encryptedAccessToken), "base64url");
  try {
    return crypto
      .privateDecrypt(
        { key: privateKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: "sha256" },
        encrypted,
      )
      .toString("utf8");
  } catch (oaepError) {
    try {
      return crypto

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Inspect the pasted payload: confirm it contains user_id (or userId) AND access_token (or accessToken/token).
  2. Complete the full OAuth flow so the final redirect includes both params; an intermediate redirect won't do.
  3. If building the payload manually, include both fields: {"user_id":"...","access_token":"..."}.
  4. Check for error params in the callback (error/error_description) — if present, re-run sign-in instead of parsing.

Example fix

// before
parseZedCallbackPayload("http://127.0.0.1/?state=xyz"); // no user_id/access_token
// after
parseZedCallbackPayload("http://127.0.0.1/?user_id=42&access_token=ENCRYPTED_B64");
Defensive patterns

Strategy: validation

Validate before calling

function hasZedCallbackFields(raw) {
  let data = {};
  try { data = JSON.parse(raw); }
  catch { try { new URL(`http://x/?${String(raw).replace(/^\?/, "")}`).searchParams.forEach((v, k) => (data[k] = v)); } catch { return false; } }
  return Boolean((data.user_id || data.userId) && (data.access_token || data.accessToken || data.token));
}

Type guard

const hasZedPayload = (d) => Boolean(d && (d.user_id || d.userId) && (d.access_token || d.accessToken || d.token));

Try / catch

try {
  const payload = parseZedCallbackPayload(input);
} catch (e) {
  if (String(e.message).includes("must include")) {
    // show which fields were found vs missing; re-run the OAuth flow
  } else throw e;
}

Prevention

When it happens

Trigger: Calling parseZedCallbackPayload with a parseable URL/JSON that lacks user_id or access_token — e.g. the redirect only carried `state`/`code` params, or the JSON contains differently-named keys.

Common situations: Zed changed its callback param names, the user pasted the initial authorize URL (which has code/state but no tokens), or the callback returned an error payload like `?error=access_denied` instead of tokens.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/b821b50991f0c4c1. Report an issue: GitHub.