Files
Scriberr/internal/api/cli_auth_handlers.go
2025-11-29 10:21:47 -08:00

90 lines
2.3 KiB
Go

package api
import (
"net/http"
"net/url"
"github.com/gin-gonic/gin"
)
// AuthorizeCLIRequest represents the request body for confirming CLI authorization
type AuthorizeCLIRequest struct {
CallbackURL string `json:"callback_url" binding:"required"`
DeviceName string `json:"device_name"`
}
// AuthorizeCLI validates the user session and returns user info for the confirmation page
// GET /api/auth/cli/authorize
func (h *Handler) AuthorizeCLI(c *gin.Context) {
// User ID is set by middleware
userID, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
return
}
// Fetch full user object
u, err := h.userRepo.FindByID(c.Request.Context(), userID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch user"})
return
}
c.JSON(http.StatusOK, gin.H{
"status": "authorized",
"user": gin.H{
"id": u.ID,
"username": u.Username,
},
})
}
// ConfirmCLIAuthorization generates a token and returns the redirect URL for the CLI
// POST /api/auth/cli/authorize
func (h *Handler) ConfirmCLIAuthorization(c *gin.Context) {
var req AuthorizeCLIRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// User ID is set by middleware
userID, exists := c.Get("user_id")
if !exists {
c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
return
}
// Fetch full user object
u, err := h.userRepo.FindByID(c.Request.Context(), userID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch user"})
return
}
// Generate long-lived token
token, err := h.authService.GenerateLongLivedToken(u)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
return
}
// Construct redirect URL
// The CLI starts a local server and expects the token in the query params
// e.g. http://localhost:xxxx?token=...
callbackURL, err := url.Parse(req.CallbackURL)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid callback URL"})
return
}
q := callbackURL.Query()
q.Set("token", token)
q.Set("username", u.Username)
callbackURL.RawQuery = q.Encode()
c.JSON(http.StatusOK, gin.H{
"redirect_url": callbackURL.String(),
})
}