mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: pass session token as query param on agent chat WebSockets (#23405)
## Problem When the Coder chat UI is embedded in a VS Code webview, the session token is set via the Coder-Session-Token header for HTTP requests. However, browsers cannot attach custom headers to WebSocket connections, and VS Code Electron webview environment does not support cookies set via Set-Cookie from iframe origins. This causes all chat WebSocket connections to fail with authorization errors. ## Solution Pass the session token as a coder_session_token query parameter on all chat-related WebSocket connections. The backend already accepts this parameter (see APITokenFromRequest in coderd/httpmw/apikey.go). The token is only included when API.getSessionToken() returns a value, which only happens in the embed bootstrap flow. Normal browser sessions use cookies and are unaffected. > Built with [Coder Agents](https://coder.com/agents)
This commit is contained in:
Generated
-23
@@ -7971,29 +7971,6 @@ const docTemplate = `{
|
||||
]
|
||||
}
|
||||
},
|
||||
"/users/me/session/token-to-cookie": {
|
||||
"post": {
|
||||
"description": "Converts the current session token into a Set-Cookie response.\nThis is used by embedded iframes (e.g. VS Code chat) that\nreceive a session token out-of-band via postMessage but need\ncookie-based auth for WebSocket connections.",
|
||||
"tags": [
|
||||
"Authorization"
|
||||
],
|
||||
"summary": "Set session token cookie",
|
||||
"operationId": "set-session-token-cookie",
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/oauth2/github/callback": {
|
||||
"get": {
|
||||
"tags": [
|
||||
|
||||
Generated
-21
@@ -7064,27 +7064,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/users/me/session/token-to-cookie": {
|
||||
"post": {
|
||||
"description": "Converts the current session token into a Set-Cookie response.\nThis is used by embedded iframes (e.g. VS Code chat) that\nreceive a session token out-of-band via postMessage but need\ncookie-based auth for WebSocket connections.",
|
||||
"tags": ["Authorization"],
|
||||
"summary": "Set session token cookie",
|
||||
"operationId": "set-session-token-cookie",
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": "No Content"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"CoderSessionToken": []
|
||||
}
|
||||
],
|
||||
"x-apidocgen": {
|
||||
"skip": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/oauth2/github/callback": {
|
||||
"get": {
|
||||
"tags": ["Users"],
|
||||
|
||||
@@ -1517,7 +1517,6 @@ func New(options *Options) *API {
|
||||
r.Post("/", api.postUser)
|
||||
r.Get("/", api.users)
|
||||
r.Post("/logout", api.postLogout)
|
||||
r.Post("/me/session/token-to-cookie", api.postSessionTokenCookie)
|
||||
r.Get("/oidc-claims", api.userOIDCClaims)
|
||||
// These routes query information about site wide roles.
|
||||
r.Route("/roles", func(r chi.Router) {
|
||||
|
||||
@@ -744,43 +744,6 @@ func (api *API) postLogout(rw http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
// @Summary Set session token cookie
|
||||
// @Description Converts the current session token into a Set-Cookie response.
|
||||
// @Description This is used by embedded iframes (e.g. VS Code chat) that
|
||||
// @Description receive a session token out-of-band via postMessage but need
|
||||
// @Description cookie-based auth for WebSocket connections.
|
||||
// @ID set-session-token-cookie
|
||||
// @Security CoderSessionToken
|
||||
// @Tags Authorization
|
||||
// @Success 204
|
||||
// @Router /users/me/session/token-to-cookie [post]
|
||||
// @x-apidocgen {"skip": true}
|
||||
func (api *API) postSessionTokenCookie(rw http.ResponseWriter, r *http.Request) {
|
||||
// Only accept the token from the Coder-Session-Token header.
|
||||
// Other sources (query params, cookies) should not be allowed
|
||||
// to bootstrap a new cookie.
|
||||
token := r.Header.Get(codersdk.SessionTokenHeader)
|
||||
if token == "" {
|
||||
httpapi.Write(r.Context(), rw, http.StatusBadRequest, codersdk.Response{
|
||||
Message: "Session token must be provided via the Coder-Session-Token header.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
apiKey := httpmw.APIKey(r)
|
||||
|
||||
cookie := api.DeploymentValues.HTTPCookies.Apply(&http.Cookie{
|
||||
Name: codersdk.SessionTokenCookie,
|
||||
Value: token,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
// Expire the cookie when the underlying API key expires.
|
||||
Expires: apiKey.ExpiresAt,
|
||||
})
|
||||
http.SetCookie(rw, cookie)
|
||||
rw.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// GithubOAuth2Team represents a team scoped to an organization.
|
||||
type GithubOAuth2Team struct {
|
||||
Organization string
|
||||
|
||||
Reference in New Issue
Block a user