Skip to main content

Authentication

A provider needs a way to authenticate requests to its backend. Where the credential comes from is an application decision: an environment variable, a secret store, an existing user login, or an organization-specific credential service. That choice should not require changing the agent's operations or conversation format.

GDK separates the HTTP authentication mechanism from the provider's request format. ApiClient accepts an AuthMethod; a custom method can ask your application for the current credential whenever it prepares a request. Provider implementations can also have their own authentication flows where a service requires them.

Authentication mechanisms​

The following mechanisms are defined in goose-providers::api_client:

MechanismUse
AuthMethod::NoAuthAn endpoint that needs no authentication, such as a suitably isolated local service.
AuthMethod::BearerTokenA token sent in the Authorization: Bearer ... header.
AuthMethod::ApiKeyA credential sent under a specified header name.
AuthMethod::CustomAn AuthProvider that supplies a header name and value at request time.

For example, an application can pass a key directly rather than rely on the goose CLI configuration:

let client = ApiClient::new_with_tls(
"https://api.openai.com".into(),
AuthMethod::BearerToken(std::env::var("OPENAI_API_KEY")?),
None,
)?;

This configures how the credential is sent; it does not install a secret store or start a login flow. The TLS argument is separate from HTTP authentication. Use a TLS-enabled build for HTTPS, and supply TlsConfig if your environment requires custom certificate authorities or a client certificate.

Provider-specific and declarative authentication​

The Databricks implementation supports token and OAuth configurations through DatabricksAuth. Its auth provider accepts application-supplied callbacks for obtaining tokens; GDK does not assume every host has the same browser login or credential storage.

Declarative providers can name an API-key variable and resolve it through KeyResolver. The supplied EnvKeyResolver uses the process environment. A definition can alternatively configure a command that obtains a credential, with caching and refresh settings. Those commands are executable configuration, so only load definitions you trust.

Supplying your own authentication​

Use AuthProvider when the credential can change during the application's lifetime or comes from a source the built-in mechanisms do not cover. For example, the host can keep the token from its own login flow in shared state:

use std::sync::{Arc, RwLock};

use anyhow::Result;
use async_trait::async_trait;
use goose_providers::api_client::AuthProvider;

struct AppAuth {
token: Arc<RwLock<String>>,
}

#[async_trait]
impl AuthProvider for AppAuth {
async fn get_auth_header(&self) -> Result<(String, String)> {
let token = self.token.read().unwrap();
Ok(("Authorization".into(), format!("Bearer {token}")))
}
}

Pass it to ApiClient as AuthMethod::Custom(Box::new(AppAuth { token })). The host can update the shared token after login or rotation without rebuilding the agent. A real credential store can replace the shared string while keeping the same trait boundary.

AuthProvider also has a refresh_credentials method. Its default reports that refresh is unsupported; implement it when your flow can refresh credentials. The provider or application decides when to invoke it. A custom header callback alone does not implement OAuth or automatic refresh.

Keep the boundaries separate​

Credentials should not be part of the conversation, prompts, tool output, or saved effects. Keep them in the application's credential handling, and avoid logging their values. A working directory is not a boundary around what an agent or its tools can access.

Authenticating a model request is also different from authenticating a client connection to goose. If your application uses the pre-built binary over ACP, the backend's provider credentials belong on the backend; a goose serve connection has its own authentication. See Build an app with goose for that path.

The full HTTP authentication and TLS APIs are in goose-providers::api_client.