Skip to content

Conversation

@huahuayu
Copy link

PR: Make Antigravity OAuth Redirect URI Dynamic

Description

This PR addresses the issue where the Antigravity OAuth callback URL was hardcoded to localhost, causing failures when deployed on remote servers with custom domains.

The changes include:

  1. pkg/antigravity: Updated BuildAuthorizationURL and ExchangeCode to accept redirectURI as a parameter instead of using a hardcoded constant.
  2. service/antigravity_oauth_service:
    • Updated GenerateAuthURL to accept redirectURI and store it in the OAuthSession.
    • Updated ExchangeCode to retrieve the redirectURI from the session and use it during token exchange.
  3. handler/admin/antigravity_oauth_handler: Updated to dynamically derive the redirect URI from the request (using Origin or X-Forwarded-* headers) and pass it to the service.

Patch

diff --git a/backend/internal/handler/admin/antigravity_oauth_handler.go b/backend/internal/handler/admin/antigravity_oauth_handler.go
index 1234567..890abcd 100644
--- a/backend/internal/handler/admin/antigravity_oauth_handler.go
+++ b/backend/internal/handler/admin/antigravity_oauth_handler.go
@@ -3,6 +3,8 @@ package admin
 import (
 	"github.com/Wei-Shaw/sub2api/internal/pkg/response"
 	"github.com/Wei-Shaw/sub2api/internal/service"
+	"fmt"
+	"strings"
 	"github.com/gin-gonic/gin"
 )
 
@@ -27,7 +29,9 @@ func (h *AntigravityOAuthHandler) GenerateAuthURL(c *gin.Context) {
 		return
 	}
 
-	result, err := h.antigravityOAuthService.GenerateAuthURL(c.Request.Context(), req.ProxyID)
+	redirectURI := deriveRedirectURI(c)
+	result, err := h.antigravityOAuthService.GenerateAuthURL(c.Request.Context(), req.ProxyID, redirectURI)
 	if err != nil {
 		response.InternalError(c, "生成授权链接失败: "+err.Error())
 		return
@@ -62,3 +66,20 @@ func (h *AntigravityOAuthHandler) ExchangeCode(c *gin.Context) {
 
 	response.Success(c, tokenInfo)
 }
+
+func deriveRedirectURI(c *gin.Context) string {
+	origin := strings.TrimSpace(c.GetHeader("Origin"))
+	if origin != "" {
+		return strings.TrimRight(origin, "/") + "/auth/callback"
+	}
+
+	scheme := "http"
+	if c.Request.TLS != nil {
+		scheme = "https"
+	}
+	if xfProto := strings.TrimSpace(c.GetHeader("X-Forwarded-Proto")); xfProto != "" {
+		scheme = strings.TrimSpace(strings.Split(xfProto, ",")[0])
+	}
+
+	host := strings.TrimSpace(c.Request.Host)
+	if xfHost := strings.TrimSpace(c.GetHeader("X-Forwarded-Host")); xfHost != "" {
+		host = strings.TrimSpace(strings.Split(xfHost, ",")[0])
+	}
+
+	return fmt.Sprintf("%s://%s/auth/callback", scheme, host)
+}
diff --git a/backend/internal/pkg/antigravity/client.go b/backend/internal/pkg/antigravity/client.go
index abcdef1..2345678 100644
--- a/backend/internal/pkg/antigravity/client.go
+++ b/backend/internal/pkg/antigravity/client.go
@@ -107,11 +107,11 @@ func shouldFallbackToNextURL(err error, statusCode int) bool {
 }
 
 // ExchangeCode 用 authorization code 交换 token
-func (c *Client) ExchangeCode(ctx context.Context, code, codeVerifier string) (*TokenResponse, error) {
+func (c *Client) ExchangeCode(ctx context.Context, code, codeVerifier, redirectURI string) (*TokenResponse, error) {
 	params := url.Values{}
 	params.Set("client_id", ClientID)
 	params.Set("client_secret", ClientSecret)
 	params.Set("code", code)
-	params.Set("redirect_uri", RedirectURI)
+	params.Set("redirect_uri", redirectURI)
 	params.Set("grant_type", "authorization_code")
 	params.Set("code_verifier", codeVerifier)
 
diff --git a/backend/internal/pkg/antigravity/oauth.go b/backend/internal/pkg/antigravity/oauth.go
index 1111111..2222222 100644
--- a/backend/internal/pkg/antigravity/oauth.go
+++ b/backend/internal/pkg/antigravity/oauth.go
@@ -21,8 +21,8 @@ const (
 	ClientID     = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com"
 	ClientSecret = "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"
 
-	// 固定的 redirect_uri(用户需手动复制 code)
-	RedirectURI = "http://localhost:8085/callback"
+	// Default RedirectURI (can be overridden)
+	DefaultRedirectURI = "http://localhost:8085/callback"
 
 	// OAuth scopes
 	Scopes = "https://www.googleapis.com/auth/cloud-platform " +
@@ -101,9 +101,12 @@ func base64URLEncode(data []byte) string {
 }
 
 // BuildAuthorizationURL 构建 Google OAuth 授权 URL
-func BuildAuthorizationURL(state, codeChallenge string) string {
+func BuildAuthorizationURL(state, codeChallenge, redirectURI string) string {
+	if redirectURI == "" {
+		redirectURI = DefaultRedirectURI
+	}
 	params := url.Values{}
 	params.Set("client_id", ClientID)
-	params.Set("redirect_uri", RedirectURI)
+	params.Set("redirect_uri", redirectURI)
 	params.Set("response_type", "code")
 	params.Set("scope", Scopes)
diff --git a/backend/internal/service/antigravity_oauth_service.go b/backend/internal/service/antigravity_oauth_service.go
index 3333333..4444444 100644
--- a/backend/internal/service/antigravity_oauth_service.go
+++ b/backend/internal/service/antigravity_oauth_service.go
@@ -30,7 +30,7 @@ func NewAntigravityOAuthService(proxyRepo *repository.ProxyRepo, sessionStore *a
 }
 
 // GenerateAuthURL 生成 Google OAuth 授权链接
-func (s *AntigravityOAuthService) GenerateAuthURL(ctx context.Context, proxyID *int64) (*AntigravityAuthURLResult, error) {
+func (s *AntigravityOAuthService) GenerateAuthURL(ctx context.Context, proxyID *int64, redirectURI string) (*AntigravityAuthURLResult, error) {
 	state, err := antigravity.GenerateState()
 	if err != nil {
 		return nil, fmt.Errorf("生成 state 失败: %w", err)
@@ -58,13 +58,14 @@ func (s *AntigravityOAuthService) GenerateAuthURL(ctx context.Context, proxyID *
 		State:        state,
 		CodeVerifier: codeVerifier,
 		ProxyURL:     proxyURL,
+		RedirectURI:  redirectURI,
 		CreatedAt:    time.Now(),
 	}
 	s.sessionStore.Set(sessionID, session)
 
 	codeChallenge := antigravity.GenerateCodeChallenge(codeVerifier)
-	authURL := antigravity.BuildAuthorizationURL(state, codeChallenge)
+	authURL := antigravity.BuildAuthorizationURL(state, codeChallenge, redirectURI)
 
 	return &AntigravityAuthURLResult{
 		AuthURL:   authURL,
@@ -88,10 +88,14 @@ func (s *AntigravityOAuthService) ExchangeCode(ctx context.Context, input *Antig
 		return nil, fmt.Errorf("state 无效")
 	}
 
+	redirectURI := session.RedirectURI
+	if redirectURI == "" {
+		redirectURI = antigravity.DefaultRedirectURI
+	}
+
 	// 确定代理 URL
 	proxyURL := session.ProxyURL
 	if input.ProxyID != nil {
@@ -104,7 +108,7 @@ func (s *AntigravityOAuthService) ExchangeCode(ctx context.Context, input *Antig
 	client := antigravity.NewClient(proxyURL)
 
 	// 交换 token
-	tokenResp, err := client.ExchangeCode(ctx, input.Code, session.CodeVerifier)
+	tokenResp, err := client.ExchangeCode(ctx, input.Code, session.CodeVerifier, redirectURI)
 	if err != nil {
 		return nil, fmt.Errorf("token 交换失败: %w", err)
 	}

@Wei-Shaw Wei-Shaw force-pushed the main branch 2 times, most recently from 624b6bc to bbdc866 Compare February 2, 2026 07:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant