diff --git a/backend/internal/pkg/oauth/oauth.go b/backend/internal/pkg/oauth/oauth.go index cfc91bee..c5ef3c6e 100644 --- a/backend/internal/pkg/oauth/oauth.go +++ b/backend/internal/pkg/oauth/oauth.go @@ -24,20 +24,18 @@ const ( RedirectURI = "https://platform.claude.com/oauth/code/callback" // Scopes - Browser URL (includes org:create_api_key for user authorization) - ScopeOAuth = "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers" + ScopeOAuth = "org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload" // Scopes - Internal API call (org:create_api_key not supported in API) - ScopeAPI = "user:profile user:inference user:sessions:claude_code user:mcp_servers" + ScopeAPI = "user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload" // Scopes - Setup token (inference only) ScopeInference = "user:inference" - // Code Verifier character set (RFC 7636 compliant) - codeVerifierCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~" - // Session TTL SessionTTL = 30 * time.Minute ) // OAuthSession stores OAuth flow state + type OAuthSession struct { State string `json:"state"` CodeVerifier string `json:"code_verifier"` @@ -147,30 +145,14 @@ func GenerateSessionID() (string, error) { 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) { - const targetLen = 32 - charsetLen := len(codeVerifierCharset) - limit := 256 - (256 % charsetLen) - - 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 - } - } - } + bytes, err := GenerateRandomBytes(32) + if err != nil { + return "", err } - - return base64URLEncode(result), nil + return base64URLEncode(bytes), nil } // GenerateCodeChallenge generates a PKCE code challenge using S256 method