coder/code-server · error · HttpError

Unauthorized

Error message

Unauthorized

What it means

The domain proxy route (domainProxy.ts:94) checks authentication for non-login requests. If the user is not authenticated and the path is not /login (which is allowed through), it throws HttpError 401 instead of proxying. This prevents unauthenticated users from reaching proxied ports via the domain-based proxy.

Source

Thrown at src/node/routes/domainProxy.ts:94

    // Assume anything that explicitly accepts text/html is a user browsing a
    // page (as opposed to an xhr request). Don't use `req.accepts()` since
    // *every* request that I've seen (in Firefox and Chromium at least)
    // includes `*/*` making it always truthy. Even for css/javascript.
    if (req.headers.accept && req.headers.accept.includes("text/html")) {
      // Let the login through.
      if (/\/login\/?/.test(req.path)) {
        return next()
      }
      // Redirect all other pages to the login.
      const to = self(req)
      return redirect(req, res, "login", {
        to: to !== "/" ? to : undefined,
      })
    }

    // Everything else gets an unauthorized message.
    throw new HttpError("Unauthorized", HttpCode.Unauthorized)
  }

  proxy.web(req, res, {
    ignorePath: true,
    target: `http://0.0.0.0:${port}${req.originalUrl}`,
  })
})

export const wsRouter = WsRouter()

wsRouter.ws(/.*/, async (req, _, next) => {
  const port = maybeProxy(req)
  if (!port) {
    return next()
  }

  ensureProxyEnabled(req)
  ensureOrigin(req)

View on GitHub (pinned to 51f90a376b)

Solutions

  1. Authenticate at code-server's /login first to obtain a valid session cookie
  2. Ensure the proxied app shares/sends the code-server session cookie
  3. For automated clients, perform the login flow then reuse the cookie for proxy requests

Example fix

// before
fetch('https://3000--user.host/proxied-path')  // 401

// after
await login('https://user.host/login', password)
fetch('https://3000--user.host/proxied-path')  // session cookie sent
Defensive patterns

Strategy: try-catch

Validate before calling

// For API clients: ensure a valid session before proxy calls
async function ensureLoggedIn(): Promise<void> {
  const r = await fetch("/api/status")
  if (r.status === 401) throw new Error("Not authenticated for domain proxy")
}

Type guard

import { HttpError, HttpCode } from "../../common/http"
function isProxyUnauthorized(e: unknown): boolean {
  return e instanceof HttpError && e.status === HttpCode.Unauthorized
}

Try / catch

try {
  // proxied request
} catch (e) {
  if (isProxyUnauthorized(e)) {
    window.location.href = `/login?to=${encodeURIComponent(window.location.href)}`
  } else throw e
}

Prevention

When it happens

Trigger: A request to a subdomain proxy URL (e.g. port-3000.codomain) without a valid session cookie and not targeting /login.

Common situations: Sessions expired while a proxied app tab was open; embedding a proxied app in another page with no cookie; race at startup where the proxied app loads before login completes.

Understand the failure class

Related errors


AI-assisted analysis of coder/code-server@51f90a376b (2026-08-12). Data as JSON: /api/errors/e31ff36ff16ce26d. Report an issue: GitHub.