decolua/9router · error · Error

No authorization code found in URL

Error message

No authorization code found in URL

What it means

handleManualSubmit throws this when the parsed callback URL has no `code` query parameter and no `error` param. A successful OAuth redirect must carry `?code=...` (plus `state`); without it the modal cannot proceed to POST /api/oauth/kiro/social-exchange to swap the code for tokens.

Source

Thrown at src/shared/components/KiroSocialOAuthModal.js:82

      // Parse callback URL - can be either kiro:// or http://localhost format
      let url;
      try {
        url = new URL(callbackUrl);
      } catch (e) {
        // If URL parsing fails, might be malformed
        throw new Error("Invalid callback URL format");
      }

      const code = url.searchParams.get("code");
      const state = url.searchParams.get("state");
      const errorParam = url.searchParams.get("error");

      if (errorParam) {
        throw new Error(url.searchParams.get("error_description") || errorParam);
      }

      if (!code) {
        throw new Error("No authorization code found in URL");
      }

      // Exchange code for tokens
      const res = await fetch("/api/oauth/kiro/social-exchange", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          code,
          codeVerifier: authData.codeVerifier,
          provider,
        }),
      });

      const data = await res.json();
      if (!res.ok) throw new Error(data.error);

      setStep("success");
      onSuccess?.();

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Re-do the authorization and copy the final browser URL after the provider redirects — it must contain ?code=...
  2. Verify you copied the full URL including query string (some browsers/apps strip it on copy).
  3. If the code appears after '#' instead of '?', the provider used the implicit flow — this modal requires the authorization-code flow; fix the provider/app config.
  4. Confirm `state` also matches what initAuth issued; a state-only URL means the redirect never completed.

Example fix

// before
if (!code) {
  throw new Error("No authorization code found in URL");
}
// after
if (!code) {
  const hashParams = new URLSearchParams(url.hash.replace(/^#/, ""));
  throw new Error(`No authorization code found in URL (params: ${[...url.searchParams.keys(), ...hashParams.keys()].join(", ") || "none"})`);
}
Defensive patterns

Strategy: validation

Validate before calling

function callbackHasCode(s) {
  try {
    const u = new URL(String(s).trim());
    const q = u.searchParams.get("code");
    const h = new URLSearchParams(u.hash.replace(/^#/, "")).get("code"); // implicit-flow fallback
    return Boolean(q || h);
  } catch { return false; }
}
if (!callbackHasCode(callbackUrl)) {
  setError("URL must contain ?code= — re-copy the address after the provider redirects back");
  return;
}

Prevention

When it happens

Trigger: User pastes a callback URL that parses but lacks `code` — e.g. they pasted the base callback/redirect URL itself, a URL that only has `state`, a logout or error page URL, or the provider put the code in the URL fragment (#code=...) instead of the query string.

Common situations: Copying the redirect_uri from app config instead of the actual redirected address; pasting the URL before completing the consent redirect; fragment-based responses (implicit flow) that this code-exchange flow doesn't support.

Related errors


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