From e74c4cf599dce51a5a18d637481096f87c3bb38e Mon Sep 17 00:00:00 2001 From: Play Life Bot Date: Fri, 2 Jan 2026 15:35:37 +0300 Subject: [PATCH] fix: use correct jwt/v5 API for OAuth state token --- play-life-backend/main.go | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/play-life-backend/main.go b/play-life-backend/main.go index 387484f..6ae68bc 100644 --- a/play-life-backend/main.go +++ b/play-life-backend/main.go @@ -5835,36 +5835,49 @@ func (a *App) updateTelegramIntegrationHandler(w http.ResponseWriter, r *http.Re sendErrorWithCORS(w, "Bot token is now configured via TELEGRAM_BOT_TOKEN environment variable", http.StatusBadRequest) } +// OAuthStateClaims структура для OAuth state JWT +type OAuthStateClaims struct { + UserID int `json:"user_id"` + Type string `json:"type"` + jwt.RegisteredClaims +} + // generateOAuthState генерирует JWT state для OAuth func generateOAuthState(userID int, jwtSecret string) (string, error) { - token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ - "user_id": userID, - "type": "todoist_oauth", - "exp": time.Now().Add(24 * time.Hour).Unix(), // 1 день - }) + claims := OAuthStateClaims{ + UserID: userID, + Type: "todoist_oauth", + RegisteredClaims: jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), // 1 день + IssuedAt: jwt.NewNumericDate(time.Now()), + }, + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString([]byte(jwtSecret)) } // validateOAuthState проверяет и извлекает user_id из JWT state func validateOAuthState(stateString string, jwtSecret string) (int, error) { - token, err := jwt.Parse(stateString, func(token *jwt.Token) (interface{}, error) { + token, err := jwt.ParseWithClaims(stateString, &OAuthStateClaims{}, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } return []byte(jwtSecret), nil }) if err != nil { return 0, err } - claims, ok := token.Claims.(jwt.MapClaims) + claims, ok := token.Claims.(*OAuthStateClaims) if !ok || !token.Valid { return 0, fmt.Errorf("invalid token") } - if claims["type"] != "todoist_oauth" { + if claims.Type != "todoist_oauth" { return 0, fmt.Errorf("wrong token type") } - userID := int(claims["user_id"].(float64)) - return userID, nil + return claims.UserID, nil } // exchangeCodeForToken обменивает OAuth code на access_token