fix: use standard PKCE code verifier generation

Replace charset→base64url double-encoding with standard random
bytes→base64url approach to match official client behavior and avoid
risk control detection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Elysia
2026-03-28 00:47:31 +08:00
parent 8fcd819e6f
commit 941c469ab9

View File

@@ -30,14 +30,12 @@ const (
// Scopes - Setup token (inference only) // Scopes - Setup token (inference only)
ScopeInference = "user:inference" ScopeInference = "user:inference"
// Code Verifier character set (RFC 7636 compliant)
codeVerifierCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
// Session TTL // Session TTL
SessionTTL = 30 * time.Minute SessionTTL = 30 * time.Minute
) )
// OAuthSession stores OAuth flow state // OAuthSession stores OAuth flow state
type OAuthSession struct { type OAuthSession struct {
State string `json:"state"` State string `json:"state"`
CodeVerifier string `json:"code_verifier"` CodeVerifier string `json:"code_verifier"`
@@ -147,30 +145,14 @@ func GenerateSessionID() (string, error) {
return hex.EncodeToString(bytes), nil return hex.EncodeToString(bytes), nil
} }
// GenerateCodeVerifier generates a PKCE code verifier using character set method // GenerateCodeVerifier generates a PKCE code verifier (RFC 7636).
// Uses 32 random bytes → base64url-no-pad, producing a 43-char verifier.
func GenerateCodeVerifier() (string, error) { func GenerateCodeVerifier() (string, error) {
const targetLen = 32 bytes, err := GenerateRandomBytes(32)
charsetLen := len(codeVerifierCharset) if err != nil {
limit := 256 - (256 % charsetLen) return "", err
result := make([]byte, 0, targetLen)
randBuf := make([]byte, targetLen*2)
for len(result) < targetLen {
if _, err := rand.Read(randBuf); err != nil {
return "", err
}
for _, b := range randBuf {
if int(b) < limit {
result = append(result, codeVerifierCharset[int(b)%charsetLen])
if len(result) >= targetLen {
break
}
}
}
} }
return base64URLEncode(bytes), nil
return base64URLEncode(result), nil
} }
// GenerateCodeChallenge generates a PKCE code challenge using S256 method // GenerateCodeChallenge generates a PKCE code challenge using S256 method