- Added extensive SDK usage guides for `cliproxy`, `sdk/access`, and watcher integration. - Introduced `--password` flag for specifying local management access passwords. - Enhanced management API with local password checks to secure localhost requests. - Updated documentation to reflect the new password functionality.
6.7 KiB
@sdk/access SDK Reference
The github.com/router-for-me/CLIProxyAPI/v6/sdk/access package centralizes inbound request authentication for the proxy. It offers a lightweight manager that chains credential providers, so servers can reuse the same access control logic inside or outside the CLI runtime.
Importing
import (
sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
)
Add the module with go get github.com/router-for-me/CLIProxyAPI/v6/sdk/access.
Manager Lifecycle
manager := sdkaccess.NewManager()
providers, err := sdkaccess.BuildProviders(cfg)
if err != nil {
return err
}
manager.SetProviders(providers)
NewManagerconstructs an empty manager.SetProvidersreplaces the provider slice using a defensive copy.Providersretrieves a snapshot that can be iterated safely from other goroutines.BuildProviderstranslatesconfig.Configaccess declarations into runnable providers. When the config omits explicit providers but defines inline API keys, the helper auto-installs the built-inconfig-api-keyprovider.
Authenticating Requests
result, err := manager.Authenticate(ctx, req)
switch {
case err == nil:
// Authentication succeeded; result describes the provider and principal.
case errors.Is(err, sdkaccess.ErrNoCredentials):
// No recognizable credentials were supplied.
case errors.Is(err, sdkaccess.ErrInvalidCredential):
// Supplied credentials were present but rejected.
default:
// Transport-level failure was returned by a provider.
}
Manager.Authenticate walks the configured providers in order. It returns on the first success, skips providers that surface ErrNotHandled, and tracks whether any provider reported ErrNoCredentials or ErrInvalidCredential for downstream error reporting.
If the manager itself is nil or no providers are registered, the call returns nil, nil, allowing callers to treat access control as disabled without branching on errors.
Each Result includes the provider identifier, the resolved principal, and optional metadata (for example, which header carried the credential).
Configuration Layout
The manager expects access providers under the auth.providers key inside config.yaml:
auth:
providers:
- name: inline-api
type: config-api-key
api-keys:
- sk-test-123
- sk-prod-456
Fields map directly to config.AccessProvider: name labels the provider, type selects the registered factory, sdk can name an external module, api-keys seeds inline credentials, and config passes provider-specific options.
Loading providers from external SDK modules
To consume a provider shipped in another Go module, point the sdk field at the module path and import it for its registration side effect:
auth:
providers:
- name: partner-auth
type: partner-token
sdk: github.com/acme/xplatform/sdk/access/providers/partner
config:
region: us-west-2
audience: cli-proxy
import (
_ "github.com/acme/xplatform/sdk/access/providers/partner" // registers partner-token
sdkaccess "github.com/router-for-me/CLIProxyAPI/v6/sdk/access"
)
The blank identifier import ensures init runs so sdkaccess.RegisterProvider executes before BuildProviders is called.
Built-in Providers
The SDK ships with one provider out of the box:
config-api-key: Validates API keys declared inline or under top-levelapi-keys. It accepts the key fromAuthorization: Bearer,X-Goog-Api-Key,X-Api-Key, or the?key=query string and reportsErrInvalidCredentialwhen no match is found.
Additional providers can be delivered by third-party packages. When a provider package is imported, it registers itself with sdkaccess.RegisterProvider.
Metadata and auditing
Result.Metadata carries provider-specific context. The built-in config-api-key provider, for example, stores the credential source (authorization, x-goog-api-key, x-api-key, or query-key). Populate this map in custom providers to enrich logs and downstream auditing.
Writing Custom Providers
type customProvider struct{}
func (p *customProvider) Identifier() string { return "my-provider" }
func (p *customProvider) Authenticate(ctx context.Context, r *http.Request) (*sdkaccess.Result, error) {
token := r.Header.Get("X-Custom")
if token == "" {
return nil, sdkaccess.ErrNoCredentials
}
if token != "expected" {
return nil, sdkaccess.ErrInvalidCredential
}
return &sdkaccess.Result{
Provider: p.Identifier(),
Principal: "service-user",
Metadata: map[string]string{"source": "x-custom"},
}, nil
}
func init() {
sdkaccess.RegisterProvider("custom", func(cfg *config.AccessProvider, root *config.Config) (sdkaccess.Provider, error) {
return &customProvider{}, nil
})
}
A provider must implement Identifier() and Authenticate(). To expose it to configuration, call RegisterProvider inside init. Provider factories receive the specific AccessProvider block plus the full root configuration for contextual needs.
Error Semantics
ErrNoCredentials: no credentials were present or recognized by any provider.ErrInvalidCredential: at least one provider processed the credentials but rejected them.ErrNotHandled: instructs the manager to fall through to the next provider without affecting aggregate error reporting.
Return custom errors to surface transport failures; they propagate immediately to the caller instead of being masked.
Integration with cliproxy Service
sdk/cliproxy wires @sdk/access automatically when you build a CLI service via cliproxy.NewBuilder. Supplying a preconfigured manager allows you to extend or override the default providers:
coreCfg, _ := config.LoadConfig("config.yaml")
providers, _ := sdkaccess.BuildProviders(coreCfg)
manager := sdkaccess.NewManager()
manager.SetProviders(providers)
svc, _ := cliproxy.NewBuilder().
WithConfig(coreCfg).
WithAccessManager(manager).
Build()
The service reuses the manager for every inbound request, ensuring consistent authentication across embedded deployments and the canonical CLI binary.
Hot reloading providers
When configuration changes, rebuild providers and swap them into the manager:
providers, err := sdkaccess.BuildProviders(newCfg)
if err != nil {
log.Errorf("reload auth providers failed: %v", err)
return
}
accessManager.SetProviders(providers)
This mirrors the behaviour in cliproxy.Service.refreshAccessProviders and api.Server.applyAccessConfig, enabling runtime updates without restarting the process.