Fix user default surface by reading JWT from cookie
The GET / route has no auth middleware, so user_id was always empty. Add UserIDFromCookie helper that opportunistically reads the sb_token cookie and extracts user_id without requiring auth. Now user preference correctly overrides the global default. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -142,6 +142,21 @@ func parseAndValidateJWT(tokenString string, jwtSecret string) (*Claims, bool) {
|
|||||||
return claims, true
|
return claims, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserIDFromCookie extracts the user ID from the sb_token cookie without
|
||||||
|
// requiring authentication. Returns "" if no valid token is found.
|
||||||
|
// Used by unauthenticated routes that want optional user context.
|
||||||
|
func UserIDFromCookie(c *gin.Context, jwtSecret string) string {
|
||||||
|
cookie, err := c.Cookie("sb_token")
|
||||||
|
if err != nil || cookie == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
claims, ok := parseAndValidateJWT(cookie, jwtSecret)
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return claims.UserID
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Auth middleware ─────────────────────────────────────────
|
// ─── Auth middleware ─────────────────────────────────────────
|
||||||
|
|
||||||
// Auth returns a Gin middleware that validates JWT bearer tokens and
|
// Auth returns a Gin middleware that validates JWT bearer tokens and
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"switchboard-core/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SeedSurfaces writes core surface manifests to the registry table.
|
// SeedSurfaces writes core surface manifests to the registry table.
|
||||||
@@ -92,9 +94,13 @@ func (e *Engine) EnabledSurfaceIDs() []string {
|
|||||||
// DefaultSurfaceRedirect returns a handler for GET / that redirects to the
|
// DefaultSurfaceRedirect returns a handler for GET / that redirects to the
|
||||||
// configured default surface, falling back to the first enabled extension
|
// configured default surface, falling back to the first enabled extension
|
||||||
// surface, then /welcome.
|
// surface, then /welcome.
|
||||||
|
//
|
||||||
|
// This route has no auth middleware, so we opportunistically read the JWT
|
||||||
|
// from the cookie to check user preferences. If the cookie is missing or
|
||||||
|
// invalid, user preference is skipped (falls through to global default).
|
||||||
func (e *Engine) DefaultSurfaceRedirect() gin.HandlerFunc {
|
func (e *Engine) DefaultSurfaceRedirect() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
userID := c.GetString("user_id")
|
userID := middleware.UserIDFromCookie(c, e.cfg.JWTSecret)
|
||||||
target := e.resolveDefaultSurface(c.Request.Context(), userID)
|
target := e.resolveDefaultSurface(c.Request.Context(), userID)
|
||||||
c.Redirect(http.StatusTemporaryRedirect, e.cfg.BasePath+target)
|
c.Redirect(http.StatusTemporaryRedirect, e.cfg.BasePath+target)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user