From 807b4c1b45b0a277c9600194736b62d9cba851e2 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Thu, 16 Apr 2026 10:06:33 -0700 Subject: [PATCH] fix(auth): allow same-origin canvas requests through WorkspaceAuth on tenant WorkspaceAuth only accepted bearer tokens, blocking the canvas from calling per-workspace routes (restart, config, secrets, chat) on the tenant image where canvas + API share the same origin. Added isSameOriginCanvas() fallback (same check used by AdminAuth): checks Referer matches request Host, gated behind CANVAS_PROXY_URL so only tenant deployments are affected. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../internal/middleware/wsauth_middleware.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/platform/internal/middleware/wsauth_middleware.go b/platform/internal/middleware/wsauth_middleware.go index 47ca268e..68c682f0 100644 --- a/platform/internal/middleware/wsauth_middleware.go +++ b/platform/internal/middleware/wsauth_middleware.go @@ -43,15 +43,21 @@ func WorkspaceAuth(database *sql.DB) gin.HandlerFunc { ctx := c.Request.Context() tok := wsauth.BearerTokenFromHeader(c.GetHeader("Authorization")) - if tok == "" { - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing workspace auth token"}) + if tok != "" { + if err := wsauth.ValidateToken(ctx, database, workspaceID, tok); err != nil { + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid workspace auth token"}) + return + } + c.Next() return } - if err := wsauth.ValidateToken(ctx, database, workspaceID, tok); err != nil { - c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid workspace auth token"}) + // Same-origin canvas on tenant image — Referer matches Host. + if isSameOriginCanvas(c) { + c.Next() return } - c.Next() + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing workspace auth token"}) + return } }