Skip to main content

Credential

Struct Credential 

Source
pub struct Credential { /* private fields */ }
Expand description

A credential for one request: a typed, redacted secret.

Attach it with HttpRequestOptions::credential, addressed to a credential scope. Only the adapter whose CredentialSlot has that scope sends it, placed where that adapter’s API expects it:

  • Credential::api_key is the provider’s own key. It replaces the key the provider was configured with.
  • Credential::header is any other authentication header, such as a gateway token (cf-aig-authorization, ocp-apim-subscription-key) or a third-party adapter’s own header. The secret is the whole header value.
use allama::ChatRequest;
use allama_http::{Credential, HttpRequestOptions};

let request = ChatRequest::new("gpt-5-mini").user("Hi").with_option(
    HttpRequestOptions::new()
        .credential("openai", Credential::api_key("sk-tenant-key"))
        .credential("openai", Credential::header("cf-aig-authorization", "Bearer gw-token")),
);
assert!(!format!("{request:?}").contains("sk-tenant-key"));

§Secrets stay in the process

Debug shows the kind and never the secret, and so does every error allama-http writes about a credential. Serializing a credential writes its kind and omits the secret, while deserializing one reads the secret: the serde impl is asymmetric on purpose, so a credential can come from a configuration file but is never written back out. The JSON form of HttpRequestOptions does not take credentials, because JSON options are exported and printed as given; deserialize the credential and attach it typed.

use allama_http::Credential;

let credential: Credential =
    serde_json::from_str(r#"{"kind": "api_key", "secret": "sk-SECRET"}"#).unwrap();
assert_eq!(credential.expose_secret(), "sk-SECRET");
assert_eq!(serde_json::to_string(&credential).unwrap(), r#"{"kind":"api_key"}"#);

§No equality, no zeroing

A credential is not PartialEq: comparing secrets is not something a request option needs, and a derived comparison would short-circuit on the first differing byte. Compare kinds, or compare expose_secret yourself, in constant time if the comparison guards anything. HttpRequestOptions, which holds credentials, is not PartialEq either.

ⓘ
use allama_http::Credential;

let _ = Credential::api_key("a") == Credential::api_key("b");

The secret is a plain String: it is not zeroed when dropped. Copies of it already live in the request headers, the HTTP client and the TLS buffers, which a Credential cannot reach, so zeroing only its own copy would promise more than it delivers. Zeroing can be added later without changing this API.

Implementations§

Source§

impl Credential

Source

pub fn api_key(secret: impl Into<String>) -> Self

The provider’s own API key.

The adapter places it as its API expects (a bearer token, an x-api-key header, …), replacing the key it was configured with.

Source

pub fn header(name: impl Into<String>, secret: impl Into<String>) -> Self

An authentication header named name, whose whole value is secret.

For gateway tokens and third-party adapters’ own headers. A header credential replaces every header of the same name the adapter set, so it is sent once. Include any scheme in the secret: Cloudflare’s gateway token is Bearer <token>.

Source

pub fn kind(&self) -> &CredentialKind

What kind of credential this is.

Source

pub fn expose_secret(&self) -> &str

The secret, for an adapter that places the credential itself (CredentialPlacement::Custom), for example to sign a request.

Never log or record it.

Source

pub fn unsupported(&self, scope: &str) -> Error

The error for a credential an adapter cannot place: an authored allama::Error::Configuration naming the kind and the scope, never the secret.

An adapter that places its credential itself returns it for a kind it does not understand, addressed to its scope, instead of falling back to its configured key, which would bill the wrong account.

Trait Implementations§

Source§

impl Clone for Credential

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Credential

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for Credential

Reads {"kind": "api_key", "secret": ".."} or {"kind": "header", "name": "..", "secret": ".."}. A serialized credential has no secret, so it does not deserialize back.

Source§

fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for Credential

Writes the kind, never the secret (see Secrets stay in the process).

Source§

fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more