Skip to content

chore: override codersdk.SessionTokenCookie in develop.sh #18991

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 23, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Revert "feat: allow prefixing coder_session_token cookie"
This reverts commit 9ce2437.
  • Loading branch information
johnstcn committed Jul 22, 2025
commit 6c86d8c720f56dd60dd2be7f2835626c7ed2b4df
2 changes: 1 addition & 1 deletion coderd/apikey.go
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ func (api *API) createAPIKey(ctx context.Context, params apikey.CreateParams) (*
})

return api.DeploymentValues.HTTPCookies.Apply(&http.Cookie{
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Value: sessionToken,
Path: "/",
HttpOnly: true,
Expand Down
2 changes: 1 addition & 1 deletion coderd/coderd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ func TestCSRFExempt(t *testing.T) {
u := client.URL.JoinPath(fmt.Sprintf("/@%s/%s.%s/apps/%s", owner.Username, wrk.Workspace.Name, agentSlug, appSlug)).String()
req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, nil)
req.AddCookie(&http.Cookie{
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Value: client.SessionToken(),
Path: "/",
Domain: client.URL.String(),
Expand Down
2 changes: 1 addition & 1 deletion coderd/coderdtest/coderdtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -1333,7 +1333,7 @@ func RequestExternalAuthCallback(t testing.TB, providerID string, client *coders
Value: state,
})
req.AddCookie(&http.Cookie{
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Value: client.SessionToken(),
})
for _, opt := range opts {
Expand Down
2 changes: 1 addition & 1 deletion coderd/coderdtest/oidctest/idp.go
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ func (f *FakeIDP) LoginWithClient(t testing.TB, client *codersdk.Client, idToken
var user *codersdk.Client
cookies := cli.Jar.Cookies(client.URL)
for _, cookie := range cookies {
if cookie.Name == codersdk.GetSessionTokenCookie() {
if cookie.Name == codersdk.SessionTokenCookie {
user = codersdk.New(client.URL)
user.SetSessionToken(cookie.Value)
}
Expand Down
2 changes: 1 addition & 1 deletion coderd/httpapi/cookie.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func StripCoderCookies(header string) string {
continue
}
name, _, _ := strings.Cut(part, "=")
if name == codersdk.GetSessionTokenCookie() ||
if name == codersdk.SessionTokenCookie ||
name == codersdk.OAuth2StateCookie ||
name == codersdk.OAuth2RedirectCookie ||
name == codersdk.PathAppSessionTokenCookie ||
Expand Down
6 changes: 3 additions & 3 deletions coderd/httpmw/apikey.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func APIKeyFromRequest(ctx context.Context, db database.Store, sessionTokenFunc
if token == "" {
return nil, codersdk.Response{
Message: SignedOutErrorMessage,
Detail: fmt.Sprintf("Cookie %q or query parameter must be provided.", codersdk.GetSessionTokenCookie()),
Detail: fmt.Sprintf("Cookie %q or query parameter must be provided.", codersdk.SessionTokenCookie),
}, false
}

Expand Down Expand Up @@ -711,12 +711,12 @@ func APITokenFromRequest(r *http.Request) string {
// Prioritize existing Coder custom authentication methods first
// to maintain backward compatibility and existing behavior

cookie, err := r.Cookie(codersdk.GetSessionTokenCookie())
cookie, err := r.Cookie(codersdk.SessionTokenCookie)
if err == nil && cookie.Value != "" {
return cookie.Value
}

urlValue := r.URL.Query().Get(codersdk.GetSessionTokenCookie())
urlValue := r.URL.Query().Get(codersdk.SessionTokenCookie)
if urlValue != "" {
return urlValue
}
Expand Down
4 changes: 2 additions & 2 deletions coderd/httpmw/apikey_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ func TestAPIKey(t *testing.T) {
rw = httptest.NewRecorder()
)
r.AddCookie(&http.Cookie{
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Value: token,
})

Expand Down Expand Up @@ -357,7 +357,7 @@ func TestAPIKey(t *testing.T) {
rw = httptest.NewRecorder()
)
q := r.URL.Query()
q.Add(codersdk.GetSessionTokenCookie(), token)
q.Add(codersdk.SessionTokenCookie, token)
r.URL.RawQuery = q.Encode()

httpmw.ExtractAPIKeyMW(httpmw.ExtractAPIKeyConfig{
Expand Down
8 changes: 4 additions & 4 deletions coderd/httpmw/csrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func CSRF(cookieCfg codersdk.HTTPCookieConfig) func(next http.Handler) http.Hand
mw := nosurf.New(next)
mw.SetBaseCookie(*cookieCfg.Apply(&http.Cookie{Path: "/", HttpOnly: true}))
mw.SetFailureHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sessCookie, err := r.Cookie(codersdk.GetSessionTokenCookie())
sessCookie, err := r.Cookie(codersdk.SessionTokenCookie)
if err == nil &&
r.Header.Get(codersdk.SessionTokenHeader) != "" &&
r.Header.Get(codersdk.SessionTokenHeader) != sessCookie.Value {
Expand All @@ -32,7 +32,7 @@ func CSRF(cookieCfg codersdk.HTTPCookieConfig) func(next http.Handler) http.Hand
fmt.Sprintf("CSRF error encountered. Authentication via %q cookie and %q header detected, but the values do not match. "+
"To resolve this issue ensure the values used in both match, or only use one of the authentication methods. "+
"You can also try clearing your cookies if this error persists.",
codersdk.GetSessionTokenCookie(), codersdk.SessionTokenHeader),
codersdk.SessionTokenCookie, codersdk.SessionTokenHeader),
http.StatusBadRequest)
return
}
Expand Down Expand Up @@ -70,7 +70,7 @@ func CSRF(cookieCfg codersdk.HTTPCookieConfig) func(next http.Handler) http.Hand
// CSRF only affects requests that automatically attach credentials via a cookie.
// If no cookie is present, then there is no risk of CSRF.
//nolint:govet
sessCookie, err := r.Cookie(codersdk.GetSessionTokenCookie())
sessCookie, err := r.Cookie(codersdk.SessionTokenCookie)
if xerrors.Is(err, http.ErrNoCookie) {
return true
}
Expand All @@ -82,7 +82,7 @@ func CSRF(cookieCfg codersdk.HTTPCookieConfig) func(next http.Handler) http.Hand
return true
}

if token := r.URL.Query().Get(codersdk.GetSessionTokenCookie()); token == sessCookie.Value {
if token := r.URL.Query().Get(codersdk.SessionTokenCookie); token == sessCookie.Value {
// If the auth is set in a url param and matches the cookie, it
// is the same as just using the url param.
return true
Expand Down
8 changes: 4 additions & 4 deletions coderd/httpmw/csrf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestCSRFExemptList(t *testing.T) {
r, err := http.NewRequestWithContext(context.Background(), http.MethodPost, c.URL, nil)
require.NoError(t, err)

r.AddCookie(&http.Cookie{Name: codersdk.GetSessionTokenCookie(), Value: "test"})
r.AddCookie(&http.Cookie{Name: codersdk.SessionTokenCookie, Value: "test"})
exempt := csrfmw.IsExempt(r)
require.Equal(t, c.Exempt, exempt)
})
Expand Down Expand Up @@ -96,7 +96,7 @@ func TestCSRFError(t *testing.T) {
req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, urlPath, nil)
require.NoError(t, err)

req.AddCookie(&http.Cookie{Name: codersdk.GetSessionTokenCookie(), Value: "session_token_value"})
req.AddCookie(&http.Cookie{Name: codersdk.SessionTokenCookie, Value: "session_token_value"})
req.AddCookie(&http.Cookie{Name: nosurf.CookieName, Value: csrfCookieValue})
req.Header.Add(nosurf.HeaderName, csrfHeaderValue)

Expand All @@ -113,7 +113,7 @@ func TestCSRFError(t *testing.T) {
req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, urlPath, nil)
require.NoError(t, err)

req.AddCookie(&http.Cookie{Name: codersdk.GetSessionTokenCookie(), Value: "session_token_value"})
req.AddCookie(&http.Cookie{Name: codersdk.SessionTokenCookie, Value: "session_token_value"})
req.AddCookie(&http.Cookie{Name: nosurf.CookieName, Value: csrfCookieValue})

rec := httptest.NewRecorder()
Expand All @@ -132,7 +132,7 @@ func TestCSRFError(t *testing.T) {
req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, urlPath, nil)
require.NoError(t, err)

req.AddCookie(&http.Cookie{Name: codersdk.GetSessionTokenCookie(), Value: "session_token_value"})
req.AddCookie(&http.Cookie{Name: codersdk.SessionTokenCookie, Value: "session_token_value"})
req.AddCookie(&http.Cookie{Name: nosurf.CookieName, Value: csrfCookieValue})
req.Header.Add(codersdk.SessionTokenHeader, "mismatched_value")

Expand Down
8 changes: 4 additions & 4 deletions coderd/httpmw/rfc6750_extended_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func TestOAuth2BearerTokenPrecedence(t *testing.T) {
req := httptest.NewRequest("GET", "/test", nil)
// Set both cookie and Bearer header - cookie should take precedence
req.AddCookie(&http.Cookie{
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Value: validToken,
})
req.Header.Set("Authorization", "Bearer invalid-token")
Expand All @@ -279,7 +279,7 @@ func TestOAuth2BearerTokenPrecedence(t *testing.T) {
// Set both query parameter and Bearer header - query should take precedence
u, _ := url.Parse("/test")
q := u.Query()
q.Set(codersdk.GetSessionTokenCookie(), validToken)
q.Set(codersdk.SessionTokenCookie, validToken)
u.RawQuery = q.Encode()

req := httptest.NewRequest("GET", u.String(), nil)
Expand Down Expand Up @@ -329,13 +329,13 @@ func TestOAuth2BearerTokenPrecedence(t *testing.T) {
u, _ := url.Parse("/test")
q := u.Query()
q.Set("access_token", validToken)
q.Set(codersdk.GetSessionTokenCookie(), validToken)
q.Set(codersdk.SessionTokenCookie, validToken)
u.RawQuery = q.Encode()

req := httptest.NewRequest("GET", u.String(), nil)
req.Header.Set("Authorization", "Bearer "+validToken)
req.AddCookie(&http.Cookie{
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Value: validToken,
})
rec := httptest.NewRecorder()
Expand Down
2 changes: 1 addition & 1 deletion coderd/httpmw/rfc6750_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func TestAPITokenFromRequest(t *testing.T) {
name: "CookiePriorityOverBearer",
setupReq: func(req *http.Request) {
req.AddCookie(&http.Cookie{
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Value: cookieToken,
})
req.Header.Set("Authorization", "Bearer "+token)
Expand Down
2 changes: 1 addition & 1 deletion coderd/httpmw/workspaceagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func ExtractWorkspaceAgentAndLatestBuild(opts ExtractWorkspaceAgentAndLatestBuil
tokenValue := APITokenFromRequest(r)
if tokenValue == "" {
optionalWrite(http.StatusUnauthorized, codersdk.Response{
Message: fmt.Sprintf("Cookie %q must be provided.", codersdk.GetSessionTokenCookie()),
Message: fmt.Sprintf("Cookie %q must be provided.", codersdk.SessionTokenCookie),
})
return
}
Expand Down
4 changes: 2 additions & 2 deletions coderd/userauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ func (api *API) postLogout(rw http.ResponseWriter, r *http.Request) {
cookie := &http.Cookie{
// MaxAge < 0 means to delete the cookie now.
MaxAge: -1,
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Path: "/",
}
http.SetCookie(rw, cookie)
Expand Down Expand Up @@ -1914,7 +1914,7 @@ func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.C
)
}
cookies = append(cookies, api.DeploymentValues.HTTPCookies.Apply(&http.Cookie{
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Path: "/",
MaxAge: -1,
HttpOnly: true,
Expand Down
2 changes: 1 addition & 1 deletion coderd/userauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2476,7 +2476,7 @@ func i64ptr(i int64) *int64 {

func authCookieValue(cookies []*http.Cookie) string {
for _, cookie := range cookies {
if cookie.Name == codersdk.GetSessionTokenCookie() {
if cookie.Name == codersdk.SessionTokenCookie {
return cookie.Value
}
}
Expand Down
4 changes: 2 additions & 2 deletions coderd/users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -618,8 +618,8 @@ func TestPostLogout(t *testing.T) {

var found bool
for _, cookie := range cookies {
if cookie.Name == codersdk.GetSessionTokenCookie() {
require.Equal(t, codersdk.GetSessionTokenCookie(), cookie.Name, "Cookie should be the auth cookie")
if cookie.Name == codersdk.SessionTokenCookie {
require.Equal(t, codersdk.SessionTokenCookie, cookie.Name, "Cookie should be the auth cookie")
require.Equal(t, -1, cookie.MaxAge, "Cookie should be set to delete")
found = true
}
Expand Down
2 changes: 1 addition & 1 deletion coderd/workspaceapps/apptest/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func appServer(t *testing.T, headers http.Header, isHTTPS bool) uint16 {
server := httptest.NewUnstartedServer(
http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
_, err := r.Cookie(codersdk.GetSessionTokenCookie())
_, err := r.Cookie(codersdk.SessionTokenCookie)
assert.ErrorIs(t, err, http.ErrNoCookie)
w.Header().Set("X-Forwarded-For", r.Header.Get("X-Forwarded-For"))
w.Header().Set("X-Got-Host", r.Host)
Expand Down
4 changes: 2 additions & 2 deletions codersdk/agentsdk/agentsdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func (c *Client) connectRPCVersion(ctx context.Context, version *apiversion.APIV
return nil, xerrors.Errorf("create cookie jar: %w", err)
}
jar.SetCookies(rpcURL, []*http.Cookie{{
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Value: c.SDK.SessionToken(),
}})
httpClient := &http.Client{
Expand Down Expand Up @@ -705,7 +705,7 @@ func (c *Client) WaitForReinit(ctx context.Context) (*ReinitializationEvent, err
return nil, xerrors.Errorf("create cookie jar: %w", err)
}
jar.SetCookies(rpcURL, []*http.Cookie{{
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Value: c.SDK.SessionToken(),
}})
httpClient := &http.Client{
Expand Down
23 changes: 1 addition & 22 deletions codersdk/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"net/http"
"net/http/httputil"
"net/url"
"os"
"strings"
"sync"

Expand All @@ -21,7 +20,6 @@ import (
"go.opentelemetry.io/otel/semconv/v1.14.0/httpconv"
"golang.org/x/xerrors"

"github.com/coder/coder/v2/buildinfo"
"github.com/coder/coder/v2/coderd/tracing"
"github.com/coder/websocket"

Expand All @@ -32,10 +30,7 @@ import (
// shouldn't be likely to conflict with any user-application set cookies.
// Be sure to strip additional cookies in httpapi.StripCoderCookies!
const (
// SessionTokenCookie represents the name of the cookie or query parameter in
// which the API key is stored.
// DEVELOPER NOTE: Please avoid referencing this value directly and use
// GetSessionTokenCookie() instead.
// SessionTokenCookie represents the name of the cookie or query parameter the API key is stored in.
SessionTokenCookie = "coder_session_token"
// SessionTokenHeader is the custom header to use for authentication.
SessionTokenHeader = "Coder-Session-Token"
Expand Down Expand Up @@ -99,22 +94,6 @@ const (
EntitlementsWarningHeader = "X-Coder-Entitlements-Warning"
)

// GetSessionTokenCookie returns the name of the session token cookie.
// In almost all production cases, this will just be SessionTokenCookie.
// However, when developing inside a Coder workspace and accessing the UI
// proxied through a Coder deployment, we need to prefix the cookie name
// to avoid conflicting with the "parent" deployment. The prefix is controlled
// by the CODER_DEV_SESSION_TOKEN_COOKIE_PREFIX environment variable, and only
// applies in development builds.
func GetSessionTokenCookie() string {
if buildinfo.IsDev() {
if pfx, found := os.LookupEnv("CODER_DEV_SESSION_TOKEN_COOKIE_PREFIX"); found && pfx != "" {
return pfx + "_" + SessionTokenCookie
}
}
return SessionTokenCookie
}

// loggableMimeTypes is a list of MIME types that are safe to log
// the output of. This is useful for debugging or testing.
var loggableMimeTypes = map[string]struct{}{
Expand Down
4 changes: 2 additions & 2 deletions codersdk/provisionerdaemons.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ func (c *Client) provisionerJobLogsAfter(ctx context.Context, path string, after
return nil, nil, xerrors.Errorf("create cookie jar: %w", err)
}
jar.SetCookies(followURL, []*http.Cookie{{
Name: GetSessionTokenCookie(),
Name: SessionTokenCookie,
Value: c.SessionToken(),
}})
httpClient := &http.Client{
Expand Down Expand Up @@ -302,7 +302,7 @@ func (c *Client) ServeProvisionerDaemon(ctx context.Context, req ServeProvisione
return nil, xerrors.Errorf("create cookie jar: %w", err)
}
jar.SetCookies(serverURL, []*http.Cookie{{
Name: GetSessionTokenCookie(),
Name: SessionTokenCookie,
Value: c.SessionToken(),
}})
httpClient.Jar = jar
Expand Down
4 changes: 2 additions & 2 deletions codersdk/workspaceagents.go
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ func (c *Client) WatchWorkspaceAgentContainers(ctx context.Context, agentID uuid
}

jar.SetCookies(reqURL, []*http.Cookie{{
Name: GetSessionTokenCookie(),
Name: SessionTokenCookie,
Value: c.SessionToken(),
}})

Expand Down Expand Up @@ -630,7 +630,7 @@ func (c *Client) WorkspaceAgentLogsAfter(ctx context.Context, agentID uuid.UUID,
return nil, nil, xerrors.Errorf("create cookie jar: %w", err)
}
jar.SetCookies(reqURL, []*http.Cookie{{
Name: GetSessionTokenCookie(),
Name: SessionTokenCookie,
Value: c.SessionToken(),
}})
httpClient := &http.Client{
Expand Down
2 changes: 1 addition & 1 deletion codersdk/workspacesdk/workspacesdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ func (c *Client) AgentReconnectingPTY(ctx context.Context, opts WorkspaceAgentRe
return nil, xerrors.Errorf("create cookie jar: %w", err)
}
jar.SetCookies(serverURL, []*http.Cookie{{
Name: codersdk.GetSessionTokenCookie(),
Name: codersdk.SessionTokenCookie,
Value: c.client.SessionToken(),
}})
httpClient = &http.Client{
Expand Down