This commit is contained in:
2025-08-26 13:57:40 -04:00
parent 39e850f8ac
commit 2a9debd9b3
3 changed files with 23 additions and 87 deletions

View File

@ -35,13 +35,12 @@ type AuthHandler struct {
// LoginPageData represents data passed to the login HTML template
type LoginPageData struct {
Token string
TokenJSON template.JS
RedirectURLJSON template.JS
TokenDeliveryJSON template.JS
ExpiresAt string
AppID string
UserID string
Token string
TokenJSON template.JS
RedirectURLJSON template.JS
ExpiresAt string
AppID string
UserID string
}
// NewAuthHandler creates a new auth handler
@ -92,7 +91,6 @@ func (h *AuthHandler) Login(c *gin.Context) {
// Handle HTML request (GET or POST with form data)
req.AppID = c.Query("app_id")
req.RedirectURI = c.Query("redirect_uri")
req.TokenDelivery = domain.TokenDeliveryMode(c.DefaultQuery("token_delivery", string(domain.TokenDeliveryQuery)))
// Parse permissions from query parameter (comma-separated)
if perms := c.Query("permissions"); perms != "" {
@ -142,56 +140,12 @@ func (h *AuthHandler) Login(c *gin.Context) {
return
}
// Handle redirect flows
tokenDelivery := req.TokenDelivery
if tokenDelivery == "" {
// Default to query delivery for redirects (external apps need token in URL)
// Only use cookie delivery if explicitly specified
tokenDelivery = domain.TokenDeliveryQuery
}
h.logger.Debug("Token delivery mode", zap.String("mode", string(tokenDelivery)))
// Generate a secure state parameter for CSRF protection
state := h.generateSecureState(userContext.UserID, req.AppID)
// Handle redirect flows - always deliver token via query parameter
var redirectURL string
switch tokenDelivery {
case domain.TokenDeliveryQuery:
// Deliver token via query parameter (for integrations like VS Code)
if req.RedirectURI != "" {
redirectURL = req.RedirectURI + "?token=" + token + "&state=" + state
}
case domain.TokenDeliveryCookie:
// Deliver token via secure cookie (default, more secure)
c.SetSameSite(http.SameSiteStrictMode)
// In development mode, make cookie accessible to JavaScript for testing
// In production, keep HTTP-only for security
httpOnly := !h.config.IsDevelopment()
secure := !h.config.IsDevelopment() // Only require HTTPS in production
c.SetCookie(
"auth_token", // name
token, // value
604800, // maxAge (7 days)
"/", // path
"", // domain (empty for current domain)
secure, // secure (HTTPS only in production)
httpOnly, // httpOnly (no JavaScript access in production)
)
// Redirect without token in URL for security
if req.RedirectURI != "" {
redirectURL = req.RedirectURI + "?state=" + state
}
default:
// Invalid delivery mode, default to cookie
if req.RedirectURI != "" {
redirectURL = req.RedirectURI + "?state=" + state
}
if req.RedirectURI != "" {
// Generate a secure state parameter for CSRF protection
state := h.generateSecureState(userContext.UserID, req.AppID)
redirectURL = req.RedirectURI + "?token=" + token + "&state=" + state
}
// Return appropriate response format
@ -202,12 +156,12 @@ func (h *AuthHandler) Login(c *gin.Context) {
c.JSON(http.StatusOK, response)
} else {
// Render HTML page
h.renderLoginPage(c, token, redirectURL, string(tokenDelivery), userContext.UserID, req.AppID)
h.renderLoginPage(c, token, redirectURL, userContext.UserID, req.AppID)
}
}
// renderLoginPage renders the HTML login page with token information
func (h *AuthHandler) renderLoginPage(c *gin.Context, token, redirectURL, tokenDelivery, userID, appID string) {
func (h *AuthHandler) renderLoginPage(c *gin.Context, token, redirectURL, userID, appID string) {
if h.loginTemplate == nil {
// Fallback to JSON if template not available
c.JSON(http.StatusOK, gin.H{
@ -223,16 +177,14 @@ func (h *AuthHandler) renderLoginPage(c *gin.Context, token, redirectURL, tokenD
// Prepare template data
tokenJSON, _ := json.Marshal(token)
redirectURLJSON, _ := json.Marshal(redirectURL)
tokenDeliveryJSON, _ := json.Marshal(tokenDelivery)
data := LoginPageData{
Token: token,
TokenJSON: template.JS(tokenJSON),
RedirectURLJSON: template.JS(redirectURLJSON),
TokenDeliveryJSON: template.JS(tokenDeliveryJSON),
ExpiresAt: time.Now().Add(7 * 24 * time.Hour).Format("Jan 2, 2006 at 3:04 PM MST"),
AppID: appID,
UserID: userID,
Token: token,
TokenJSON: template.JS(tokenJSON),
RedirectURLJSON: template.JS(redirectURLJSON),
ExpiresAt: time.Now().Add(7 * 24 * time.Hour).Format("Jan 2, 2006 at 3:04 PM MST"),
AppID: appID,
UserID: userID,
}
c.Header("Content-Type", "text/html; charset=utf-8")