diff --git a/internal/domain/models.go b/internal/domain/models.go index 76cfb5a..dfa42f2 100644 --- a/internal/domain/models.go +++ b/internal/domain/models.go @@ -124,20 +124,11 @@ type VerifyResponse struct { Error string `json:"error,omitempty"` } -// TokenDeliveryMode specifies how tokens should be delivered in redirect flows -type TokenDeliveryMode string - -const ( - TokenDeliveryCookie TokenDeliveryMode = "cookie" // Token in secure cookie (default) - TokenDeliveryQuery TokenDeliveryMode = "query" // Token in query parameter (for integrations) -) - // LoginRequest represents a user login request type LoginRequest struct { - AppID string `json:"app_id" validate:"required"` - Permissions []string `json:"permissions,omitempty"` - RedirectURI string `json:"redirect_uri,omitempty"` - TokenDelivery TokenDeliveryMode `json:"token_delivery,omitempty"` // How to deliver token in redirect flows + AppID string `json:"app_id" validate:"required"` + Permissions []string `json:"permissions,omitempty"` + RedirectURI string `json:"redirect_uri,omitempty"` } // LoginResponse represents a user login response diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index eb5a90e..2df152a 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -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") diff --git a/templates/login.html b/templates/login.html index 5de35f4..b37f1de 100644 --- a/templates/login.html +++ b/templates/login.html @@ -157,7 +157,6 @@ // Token and redirect information from server const token = {{.TokenJSON}}; const redirectURL = {{.RedirectURLJSON}}; - const tokenDelivery = {{.TokenDeliveryJSON}}; // Elements const loadingDiv = document.getElementById('loading'); @@ -229,13 +228,7 @@ setTimeout(performRedirect, 1000); }); - // Handle cookie-based token delivery - if (tokenDelivery === 'cookie') { - document.addEventListener('DOMContentLoaded', function() { - const message = document.querySelector('.redirect-info'); - message.innerHTML += '
Delivery method: Secure cookie (auth_token)'; - }); - } + // Token is always delivered via query parameter \ No newline at end of file