From ac3ca0ad8e10f60bdec90376873bcc76e6f9908e Mon Sep 17 00:00:00 2001 From: zhiqing0205 <1775840762@qq.com> Date: Tue, 6 Jan 2026 02:25:56 +0800 Subject: [PATCH] feat(codex): include plan type in auth filename --- .../api/handlers/management/auth_files.go | 7 ++- internal/auth/codex/filename.go | 55 +++++++++++++++++++ sdk/auth/codex.go | 8 ++- 3 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 internal/auth/codex/filename.go diff --git a/internal/api/handlers/management/auth_files.go b/internal/api/handlers/management/auth_files.go index e0904ab6..ad35bb9b 100644 --- a/internal/api/handlers/management/auth_files.go +++ b/internal/api/handlers/management/auth_files.go @@ -1377,9 +1377,11 @@ func (h *Handler) RequestCodexToken(c *gin.Context) { claims, _ := codex.ParseJWTToken(tokenResp.IDToken) email := "" accountID := "" + planType := "" if claims != nil { email = claims.GetUserEmail() accountID = claims.GetAccountID() + planType = strings.TrimSpace(claims.CodexAuthInfo.ChatgptPlanType) } // Build bundle compatible with existing storage bundle := &codex.CodexAuthBundle{ @@ -1396,10 +1398,11 @@ func (h *Handler) RequestCodexToken(c *gin.Context) { // Create token storage and persist tokenStorage := openaiAuth.CreateTokenStorage(bundle) + fileName := codex.CredentialFileName(tokenStorage.Email, planType, true) record := &coreauth.Auth{ - ID: fmt.Sprintf("codex-%s.json", tokenStorage.Email), + ID: fileName, Provider: "codex", - FileName: fmt.Sprintf("codex-%s.json", tokenStorage.Email), + FileName: fileName, Storage: tokenStorage, Metadata: map[string]any{ "email": tokenStorage.Email, diff --git a/internal/auth/codex/filename.go b/internal/auth/codex/filename.go new file mode 100644 index 00000000..7eeedce6 --- /dev/null +++ b/internal/auth/codex/filename.go @@ -0,0 +1,55 @@ +package codex + +import ( + "fmt" + "strings" + "unicode" +) + +// CredentialFileName returns the filename used to persist Codex OAuth credentials. +// When planType is available (e.g. "plus", "team"), it is appended after the email +// as a suffix to disambiguate subscriptions. +func CredentialFileName(email, planType string, includeProviderPrefix bool) string { + email = strings.TrimSpace(email) + plan := normalizePlanTypeForFilename(planType) + + prefix := "" + if includeProviderPrefix { + prefix = "codex-" + } + + if plan == "" { + return fmt.Sprintf("%s%s.json", prefix, email) + } + return fmt.Sprintf("%s%s-%s.json", prefix, email, plan) +} + +func normalizePlanTypeForFilename(planType string) string { + planType = strings.TrimSpace(planType) + if planType == "" { + return "" + } + + parts := strings.FieldsFunc(planType, func(r rune) bool { + return !unicode.IsLetter(r) && !unicode.IsDigit(r) + }) + if len(parts) == 0 { + return "" + } + + for i, part := range parts { + parts[i] = titleToken(part) + } + return strings.Join(parts, "-") +} + +func titleToken(token string) string { + token = strings.TrimSpace(token) + if token == "" { + return "" + } + lower := strings.ToLower(token) + runes := []rune(lower) + runes[0] = unicode.ToUpper(runes[0]) + return string(runes) +} diff --git a/sdk/auth/codex.go b/sdk/auth/codex.go index 99992525..af57f180 100644 --- a/sdk/auth/codex.go +++ b/sdk/auth/codex.go @@ -186,7 +186,13 @@ waitForCallback: return nil, fmt.Errorf("codex token storage missing account information") } - fileName := fmt.Sprintf("codex-%s.json", tokenStorage.Email) + planType := "" + if tokenStorage.IDToken != "" { + if claims, errParse := codex.ParseJWTToken(tokenStorage.IDToken); errParse == nil && claims != nil { + planType = strings.TrimSpace(claims.CodexAuthInfo.ChatgptPlanType) + } + } + fileName := codex.CredentialFileName(tokenStorage.Email, planType, true) metadata := map[string]any{ "email": tokenStorage.Email, }