pub trait CredentialBroker: Send + Sync {
Show 19 methods
// Required methods
fn access_token<'life0, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
fn proxy<'life0, 'async_trait>(
&'life0 self,
request: ProxyRequest,
) -> Pin<Box<dyn Future<Output = Result<ProxyResponse, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
fn proxy_stream<'life0, 'async_trait>(
&'life0 self,
request: ProxyRequest,
) -> Pin<Box<dyn Future<Output = Result<Pin<Box<dyn Stream<Item = Result<Bytes, BrokerError>> + Send>>, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
fn anthropic_usage<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Value, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
fn capabilities<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<ProviderStatus>, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait;
// Provided methods
fn account_selector(&self, provider: OAuthProviderId) -> AccountSelector { ... }
fn access_token_for<'life0, 'life1, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn recover_rejected_token<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
_rejected: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
fn access_token_pinned<'life0, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
) -> Pin<Box<dyn Future<Output = Result<PinnedToken, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait { ... }
fn access_token_pinned_for<'life0, 'life1, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
model: Option<&'life1 str>,
) -> Pin<Box<dyn Future<Output = Result<PinnedToken, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn access_token_pinned_excluding<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
model: Option<&'life1 str>,
exclude: &'life2 [CredentialRef],
) -> Pin<Box<dyn Future<Output = Result<PinnedToken, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
fn accounts<'life0, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
) -> Pin<Box<dyn Future<Output = Result<Vec<AccountSummary>, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
Self: 'async_trait { ... }
fn usage<'life0, 'life1, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
) -> Pin<Box<dyn Future<Output = Result<UsageSnapshot, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn report_cooldown<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
until_ms: Option<u64>,
reason: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
fn active_cooldown(&self, cred: &CredentialRef) -> Option<u64> { ... }
fn clear_cooldown(&self, cred: &CredentialRef, sent_at_ms: u64) { ... }
fn access_token_for_auto<'life0, 'life1, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn cloud_catalog<'life0, 'life1, 'async_trait>(
&'life0 self,
provider: CloudProviderId,
context_ref: &'life1 str,
allow_stale: bool,
) -> Pin<Box<dyn Future<Output = Result<Vec<CloudCatalogEntry>, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn cloud_invoke<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
provider: CloudProviderId,
context_ref: &'life1 str,
model_id: &'life2 str,
request: InvokeRequest,
) -> Pin<Box<dyn Future<Output = Result<Pin<Box<dyn Stream<Item = Result<CloudEvent, BrokerError>> + Send>>, BrokerError>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
}Expand description
The typed credential broker protocol. One implementation runs in-process
(LocalBroker) so normal local use needs no daemon; the other talks to a
remote synaps auth-broker over authenticated HTTP(S) (RemoteBroker).
Required Methods§
Sourcefn access_token<'life0, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn access_token<'life0, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Vend a fresh OAuth access token (token + expiry ONLY) for the
policy-selected account of provider.
Sourcefn proxy<'life0, 'async_trait>(
&'life0 self,
request: ProxyRequest,
) -> Pin<Box<dyn Future<Output = Result<ProxyResponse, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn proxy<'life0, 'async_trait>(
&'life0 self,
request: ProxyRequest,
) -> Pin<Box<dyn Future<Output = Result<ProxyResponse, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Execute a non-streaming provider request with the broker-owned key.
Sourcefn proxy_stream<'life0, 'async_trait>(
&'life0 self,
request: ProxyRequest,
) -> Pin<Box<dyn Future<Output = Result<Pin<Box<dyn Stream<Item = Result<Bytes, BrokerError>> + Send>>, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn proxy_stream<'life0, 'async_trait>(
&'life0 self,
request: ProxyRequest,
) -> Pin<Box<dyn Future<Output = Result<Pin<Box<dyn Stream<Item = Result<Bytes, BrokerError>> + Send>>, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Execute a streaming (SSE) provider request with the broker-owned key.
Returns the byte stream only when the upstream response is successful;
error statuses are read (bounded) and surfaced as BrokerError.
Sourcefn anthropic_usage<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Value, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn anthropic_usage<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Value, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Typed operation: fetch the Anthropic account-usage summary.
The destination URL is pinned broker-side and the OAuth access token
is resolved and attached behind the boundary — callers receive usage
JSON only and never see a token or auth.json. This is deliberately
NOT a generic OAuth proxy: one operation, one fixed endpoint.
Sourcefn capabilities<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<ProviderStatus>, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn capabilities<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<ProviderStatus>, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Non-secret provider capability/status list.
Provided Methods§
Sourcefn account_selector(&self, provider: OAuthProviderId) -> AccountSelector
fn account_selector(&self, provider: OAuthProviderId) -> AccountSelector
Effective account selector for provider (env > config > injected
policy). No I/O beyond reading configuration; no secrets.
Sourcefn access_token_for<'life0, 'life1, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn access_token_for<'life0, 'life1, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Vend a token for an explicitly addressed credential. The default
implementation serves only the default slot (via access_token);
a named slot is an error — NEVER a fallback to another account.
Sourcefn recover_rejected_token<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
_rejected: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn recover_rejected_token<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
_rejected: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Re-vend the exact credential whose access token was rejected. Local brokers force refresh only if storage still holds that rejected token. Remote/custom brokers keep their ordinary explicit-slot semantics.
Sourcefn access_token_pinned<'life0, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
) -> Pin<Box<dyn Future<Output = Result<PinnedToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn access_token_pinned<'life0, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
) -> Pin<Box<dyn Future<Output = Result<PinnedToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Policy-resolved pair: the credential the broker selected for
provider and its token. Default implementation: the default slot.
Sourcefn access_token_pinned_for<'life0, 'life1, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
model: Option<&'life1 str>,
) -> Pin<Box<dyn Future<Output = Result<PinnedToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn access_token_pinned_for<'life0, 'life1, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
model: Option<&'life1 str>,
) -> Pin<Box<dyn Future<Output = Result<PinnedToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Model-aware variant of access_token_pinned: under an auto
selector only accounts with proven capacity for model are
eligible. Default implementation ignores the model.
Sourcefn access_token_pinned_excluding<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
model: Option<&'life1 str>,
exclude: &'life2 [CredentialRef],
) -> Pin<Box<dyn Future<Output = Result<PinnedToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn access_token_pinned_excluding<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
model: Option<&'life1 str>,
exclude: &'life2 [CredentialRef],
) -> Pin<Box<dyn Future<Output = Result<PinnedToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
access_token_pinned_for that never answers with an account in
exclude (the accounts one logical request already used). Default
implementation: the ordinary selection, with an excluded answer
refused as “no account available”; a broker that can pass the
exclusion into its own selection overrides this.
Sourcefn accounts<'life0, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
) -> Pin<Box<dyn Future<Output = Result<Vec<AccountSummary>, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
fn accounts<'life0, 'async_trait>(
&'life0 self,
provider: OAuthProviderId,
) -> Pin<Box<dyn Future<Output = Result<Vec<AccountSummary>, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
Self: 'async_trait,
Non-secret account listing for provider. Default: unsupported.
Sourcefn usage<'life0, 'life1, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
) -> Pin<Box<dyn Future<Output = Result<UsageSnapshot, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn usage<'life0, 'life1, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
) -> Pin<Box<dyn Future<Output = Result<UsageSnapshot, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Typed, read-only usage snapshot for one credential. The token is resolved and used behind the boundary; callers receive normalized, secret-free data only. Default: unsupported.
Sourcefn report_cooldown<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
until_ms: Option<u64>,
reason: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn report_cooldown<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
until_ms: Option<u64>,
reason: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Report that cred hit a provider limit so automatic selection stops
advertising it until until_ms (epoch ms; None = a short default).
Best effort; default implementation is a no-op.
Sourcefn active_cooldown(&self, cred: &CredentialRef) -> Option<u64>
fn active_cooldown(&self, cred: &CredentialRef) -> Option<u64>
When cred’s active cooldown ends (epoch ms), if this broker knows
of one. No network request and no token refresh. Default: none.
Sourcefn clear_cooldown(&self, cred: &CredentialRef, sent_at_ms: u64)
fn clear_cooldown(&self, cred: &CredentialRef, sent_at_ms: u64)
A request sent on cred at sent_at_ms (epoch ms) was accepted:
drop its cooldown if that was reported no later than the request
left (the same millisecond counts: the caller saw the limit first), so
a limit that has passed does not keep moving turns off the account.
A cooldown reported later than sent_at_ms stays (that request proves
nothing about it). Memory only. Default: no-op.
Sourcefn access_token_for_auto<'life0, 'life1, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn access_token_for_auto<'life0, 'life1, 'async_trait>(
&'life0 self,
cred: &'life1 CredentialRef,
) -> Pin<Box<dyn Future<Output = Result<AccessToken, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Re-vend cred for automatic selection (a turn keeping the account
it is on). Unlike access_token_for, which serves an account the
user chose, this honours and records a refused refresh’s hold, the
same as the automatic choice’s own vend. Default:
access_token_for.
Sourcefn cloud_catalog<'life0, 'life1, 'async_trait>(
&'life0 self,
provider: CloudProviderId,
context_ref: &'life1 str,
allow_stale: bool,
) -> Pin<Box<dyn Future<Output = Result<Vec<CloudCatalogEntry>, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn cloud_catalog<'life0, 'life1, 'async_trait>(
&'life0 self,
provider: CloudProviderId,
context_ref: &'life1 str,
allow_stale: bool,
) -> Pin<Box<dyn Future<Output = Result<Vec<CloudCatalogEntry>, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Typed cloud catalog. Credentials and provider authority remain broker-owned.
Sourcefn cloud_invoke<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
provider: CloudProviderId,
context_ref: &'life1 str,
model_id: &'life2 str,
request: InvokeRequest,
) -> Pin<Box<dyn Future<Output = Result<Pin<Box<dyn Stream<Item = Result<CloudEvent, BrokerError>> + Send>>, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn cloud_invoke<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
provider: CloudProviderId,
context_ref: &'life1 str,
model_id: &'life2 str,
request: InvokeRequest,
) -> Pin<Box<dyn Future<Output = Result<Pin<Box<dyn Stream<Item = Result<CloudEvent, BrokerError>> + Send>>, BrokerError>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Typed cloud invocation. The canonical model and normalized request are the only caller-controlled inputs; hosts, auth and signing remain broker-owned.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".