decolua/9router · warning · Error

`xai discovery ${field} must use https: ${value}`

Error message

`xai discovery ${field} must use https: ${value}`

What it means

validateXaiOAuthEndpoint requires discovered xAI endpoints to use https; any http:, ftp:, or custom-scheme URL is rejected with this error naming the offending field and value. This prevents OAuth tokens from being sent over plaintext or to unexpected schemes. discoverXaiEndpoints catches it and falls back to the static https x.ai endpoints.

Source

Thrown at src/lib/oauth/providerHelpers.js:10

const BASE64_BLOCK_SIZE = 4;

function validateXaiOAuthEndpoint(rawUrl, field) {
  const value = String(rawUrl || "").trim();
  if (!value) throw new Error(`xai discovery ${field} is empty`);
  let parsed;
  try { parsed = new URL(value); } catch (err) {
    throw new Error(`xai discovery ${field} is invalid: ${err.message}`);
  }
  if (parsed.protocol !== "https:") throw new Error(`xai discovery ${field} must use https: ${value}`);
  const host = parsed.hostname.toLowerCase().trim();
  if (host !== "x.ai" && !host.endsWith(".x.ai")) {
    throw new Error(`xai discovery ${field} host ${host} is not on x.ai`);
  }
  return value;
}

function decodeXaiIdTokenEmail(idToken) {
  if (!idToken || typeof idToken !== "string") return undefined;
  const parts = idToken.split(".");
  if (parts.length !== 3) return undefined;
  try {
    const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
    const padding = (BASE64_BLOCK_SIZE - (base64.length % BASE64_BLOCK_SIZE)) % BASE64_BLOCK_SIZE;
    const json = Buffer.from(base64 + "=".repeat(padding), "base64").toString("utf8");
    const payload = JSON.parse(json);
    return payload.email || payload.preferred_username || payload.sub || undefined;
  } catch {

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Use the https form of the endpoint (https://x.ai/...) — plain http is never accepted here.
  2. Rely on discoverXaiEndpoints' static fallback (XAI_CONFIG endpoints are https).
  3. If testing locally, point code at the real discovery URL or pre-validate yourself without the https check.
  4. Check for a proxy stripping TLS / rewriting scheme in the discovery payload.

Example fix

// before
validateXaiOAuthEndpoint('http://x.ai/oauth/token', 'token_endpoint'); // throws
// after
validateXaiOAuthEndpoint('https://x.ai/oauth/token', 'token_endpoint');
Defensive patterns

Strategy: validation

Validate before calling

function isHttpsUrl(v) {
  try { return new URL(String(v).trim()).protocol === 'https:'; } catch { return false; }
}
// if (!isHttpsUrl(data.authorization_endpoint)) use static https fallback

Type guard

function isHttpsEndpoint(v) {
  if (typeof v !== 'string') return false;
  try { return new URL(v.trim()).protocol === 'https:'; } catch { return false; }
}

Try / catch

try {
  const url = validateXaiOAuthEndpoint(raw, 'token_endpoint');
  // use url
} catch (err) {
  if (/must use https:/.test(err.message)) {
    // reject or fall back to the static https x.ai endpoint
    return XAI_CONFIG.tokenUrl;
  }
  throw err;
}

Prevention

When it happens

Trigger: Discovery document (or direct caller) supplies an endpoint with a non-https protocol, e.g. 'http://x.ai/oauth/token' or a localhost 'http://127.0.0.1:8080/token' endpoint from a test/mock discovery response.

Common situations: Local development mock discovery servers that advertise http endpoints, tampered/proxied discovery responses, or copied http URLs pasted into custom config.

Related errors


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