How the Cookie Suffix Prevents Authentication Cookie Collisions in Multi-Instance code-server Deployments

The --cookie-suffix flag generates a unique session cookie name per instance, ensuring browsers store separate authentication tokens for each code-server deployment sharing the same domain.

When running multiple code-server instances behind a reverse proxy or across Kubernetes pods, authentication cookie collisions can cause users to be unexpectedly logged out or authenticated against the wrong instance. The cookie suffix feature in coder/code-server solves this by appending a unique identifier to the session cookie name, creating namespace isolation at the browser storage level.

By default, code-server stores session tokens in a cookie named code-server-session. When several instances are reachable under the same domain (e.g., multiple pods behind a load balancer or different sub-paths on a shared host), the browser treats these as the same cookie scope. The last instance to set a cookie overwrites the others, causing requests to any instance to send the wrong authentication token. This breaks logout functionality and session validation for all but the most recently accessed instance.

In src/common/http.ts, the getCookieSessionName function dynamically constructs the cookie name based on an optional suffix parameter:

export function getCookieSessionName(suffix?: string): string {
  return suffix
    ? `code-server-session-${suffix.replace(/[^a-zA-Z0-9-]/g, "-")}`
    : "code-server-session"
}

The function sanitizes the suffix by replacing any non-alphanumeric characters (except hyphens) with dashes, ensuring URL-safe cookie names. When a suffix is provided, the resulting cookie name becomes code-server-session-${suffix}, creating a unique storage key that browsers treat as distinct from other instances.

Configuration via CLI and Environment Variables

As implemented in src/node/cli.ts (lines 76-81), users specify the suffix through either the --cookie-suffix flag or the CODE_SERVER_COOKIE_SUFFIX environment variable. This value propagates through the application to the cookie generation logic, allowing per-instance customization without code changes.

Implementation Across the Request Lifecycle

Route Handler Integration

During startup, src/node/routes/index.ts (lines 64-81) attaches the generated cookie name to every incoming request as req.cookieSessionName. This ensures all route handlers reference the identical cookie name throughout the request lifecycle:

// Simplified excerpt from routes/index.ts
req.cookieSessionName = getCookieSessionName(cookieSuffix);

After successful password validation, src/node/routes/login.ts (lines 96-99) sets the authentication cookie using the suffix-aware name:

res.cookie(req.cookieSessionName, hashedPassword, getCookieOptions(req));

This stores the session token in a browser cookie scoped specifically to this instance's suffix.

The logout handler in src/node/routes/logout.ts (lines 7-10) clears the cookie using the exact same name and options:

res.clearCookie(req.cookieSessionName, getCookieOptions(req));

Critically, both operations invoke getCookieOptions from src/node/http.ts (lines 20-30 and 98-104) to ensure identical domain, path, and sameSite attributes. This guarantees the browser removes exactly the cookie that was set, preventing orphaned tokens or clearance failures.

To run two code-server instances on the same domain without authentication conflicts:


# Instance A - production environment

code-server --bind-addr 0.0.0.0:8080 --cookie-suffix prodA &

# Instance B - staging environment  

code-server --bind-addr 0.0.0.0:8081 --cookie-suffix prodB &

The browser now maintains two independent cookies:


code-server-session-prodA=<token_a>
code-server-session-prodB=<token_b>

Because browsers index cookies by the combination of name + domain + path, these tokens coexist without overwriting each other. Users remain authenticated to both instances simultaneously, and logout actions affect only the targeted instance.

Summary

  • Default cookie names collide when multiple code-server instances share a domain, causing browsers to overwrite session tokens.
  • The suffix mechanism in src/common/http.ts generates unique cookie names like code-server-session-prodA via getCookieSessionName.
  • Configuration flexibility allows setting the suffix via --cookie-suffix CLI flag or CODE_SERVER_COOKIE_SUFFIX environment variable.
  • Consistent cookie options through getCookieOptions ensure login and logout operations target the same browser storage key.
  • Multi-instance safety enables Kubernetes pods, Docker Swarm services, and reverse-proxy sub-paths to maintain isolated authentication sessions.

Frequently Asked Questions

Without a suffix, all instances use the default code-server-session name. The browser stores only one cookie per domain/path combination, meaning the most recently visited instance overwrites the others' session tokens. This causes authentication failures and forces users to re-login when switching between instances.

Yes. The getCookieSessionName function in src/common/http.ts automatically sanitizes the suffix by replacing any characters that are not alphanumeric or hyphens with dashes using the regex /[^a-zA-Z0-9-]/g. This ensures the resulting cookie name complies with browser cookie naming standards.

No. The suffix only modifies the cookie name. Security attributes including HttpOnly, Secure, and SameSite are determined separately by getCookieOptions in src/node/http.ts and remain consistent regardless of the suffix value.

Set the CODE_SERVER_COOKIE_SUFFIX environment variable in your pod specification, using values derived from the pod name, namespace, or deployment stage. For example, CODE_SERVER_COOKIE_SUFFIX=prod-pod-$(POD_NAME) ensures each replica maintains isolated sessions while sharing the same service domain.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →