Add user:pass Basic auth mode for API-key connectors

The API-key connection transport could present a key as a Bearer token,
an x-api-key header, a custom scheme (SSWS/Token), or HTTP Basic with an
empty password (Cursor). None of these can carry a real password, which
providers such as ClickHouse Cloud (keyId:keySecret) and Langfuse
(publicKey:secretKey) require.

Add a fourth mode, APIKeyBasicAuthUserPass, that base64-encodes the
stored "username:password" credential verbatim into Authorization: Basic.
SetBasicAuth cannot express this -- it re-appends a ":" and corrupts the
credential. The mode is wired generically through the registry and the
create-connector resolver and is mutually exclusive with the other
API-key auth modes.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
This commit is contained in:
Aurélien Sibiril
2026-06-12 19:52:58 +02:00
parent 897ca031e2
commit bd6a470d6d
6 changed files with 125 additions and 9 deletions

View File

@@ -71,16 +71,21 @@ func (r *Registry) Register(reg *Registration) error {
return fmt.Errorf("cannot register connector provider %q: missing DisplayName", reg.Provider)
}
// APIKeyBasicAuth, APIKeyHeader, and APIKeyAuthScheme select different
// presentations of the same key; setting more than one is a programmer
// error with a silent winner (Client checks BasicAuth, then Header,
// then Scheme). Reject it at startup.
// APIKeyBasicAuth, APIKeyBasicAuthUserPass, APIKeyHeader, and
// APIKeyAuthScheme select different presentations of the same key;
// setting more than one is a programmer error with a silent winner
// (Client checks BasicAuth, then BasicAuthUserPass, then Header, then
// Scheme). Reject it at startup.
apiKeyModes := 0
if reg.APIKeyBasicAuth {
apiKeyModes++
}
if reg.APIKeyBasicAuthUserPass {
apiKeyModes++
}
if reg.APIKeyHeader != "" {
apiKeyModes++
}
@@ -90,7 +95,7 @@ func (r *Registry) Register(reg *Registration) error {
}
if apiKeyModes > 1 {
return fmt.Errorf("cannot register connector provider %q: APIKeyBasicAuth, APIKeyHeader, and APIKeyAuthScheme are mutually exclusive", reg.Provider)
return fmt.Errorf("cannot register connector provider %q: APIKeyBasicAuth, APIKeyBasicAuthUserPass, APIKeyHeader, and APIKeyAuthScheme are mutually exclusive", reg.Provider)
}
// BuildTokenURLForDomain and BuildTokenURLForSite both build the token
@@ -206,6 +211,19 @@ func (r *Registry) APIKeyAuthScheme(p coredata.ConnectorProvider) string {
return ""
}
// APIKeyUsesBasicAuthUserPass reports whether an API-key connection for the
// given provider must present its key as a complete HTTP Basic credential
// (`username:password` already encoded in the key, base64'd verbatim)
// instead of a Bearer token. Returns false for unknown providers and for
// providers that use the default Bearer scheme.
func (r *Registry) APIKeyUsesBasicAuthUserPass(p coredata.ConnectorProvider) bool {
if reg, ok := r.Get(p); ok {
return reg.APIKeyBasicAuthUserPass
}
return false
}
// ProviderOAuth2Scopes returns the OAuth2 scopes the access review
// driver for the given provider needs to list user accounts. Returns
// nil for providers that do not need any scopes (Notion, Intercom)