config

package
v1.52.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 24, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// TokenEndpoint is the path of the Anthropic OAuth 2.0 token
	// endpoint — the destination for jwt-bearer exchanges,
	// refresh_token grants, and (future) authorization_code grants.
	TokenEndpoint = "/v1/oauth/token"

	// GrantTypeJWTBearer is the RFC 7523 grant type string used for
	// OIDC federation exchanges.
	GrantTypeJWTBearer = "urn:ietf:params:oauth:grant-type:jwt-bearer"

	// GrantTypeRefreshToken is the RFC 6749 §6 grant type string used
	// for rotating user_oauth access tokens.
	GrantTypeRefreshToken = "refresh_token"

	// OAuthAPIBetaHeader is the anthropic-beta value required on
	// authenticated API requests using an OAuth bearer token, and on
	// refresh_token grants against the token endpoint.
	OAuthAPIBetaHeader = "oauth-2025-04-20"

	// FederationBetaHeader is the anthropic-beta value required on
	// jwt-bearer exchanges against the token endpoint. It routes the
	// request to the Go userauth service; it must NOT be sent on
	// refresh_token grants, which are gateway-routed to the Python
	// oauth-server.
	FederationBetaHeader = "oidc-federation-2026-04-01"
)

OAuth 2.0 wire-contract constants. These are the authoritative definitions; internal/auth re-exports them as local aliases so that in-tree auth code can reference them without importing config and forming a cycle.

View Source
const ConfigFileVersion = "1.0"

ConfigFileVersion is the version written to configs/<profile>.json. Absent on read implies "1.0". Two-part major.minor: bump major on backwards- incompatible shape changes (readers can reject), minor on additive changes that older readers can tolerate.

View Source
const CredentialsFileVersion = "1.0"

CredentialsFileVersion is the version written to credentials/<profile>.json. Absent on read implies "1.0". Major.minor format: bump major on backwards-incompatible shape changes, minor on additive changes.

View Source
const OAuthErrorBodyMaxLen = 2000

OAuthErrorBodyMaxLen caps the error body length embedded in OAuth-endpoint failure error messages. Token-endpoint responses are untrusted and are routinely captured in logs; the cap covers identity-provider proxies that concatenate upstream messages into error_description.

Variables

This section is empty.

Functions

func ActiveConfigPath

func ActiveConfigPath(dir string) string

ActiveConfigPath returns the path to the active_config pointer file under dir.

func CredentialsDir

func CredentialsDir(dir string) string

CredentialsDir returns the directory containing per-profile credentials files.

func DefaultDir

func DefaultDir() string

DefaultDir returns the SDK's default configuration directory (the same one LoadConfig reads from when ANTHROPIC_CONFIG_DIR is unset). Returns an empty string if the platform home directory cannot be resolved — the writers in this package surface that as an explicit error.

func DeleteProfile

func DeleteProfile(dir, profile string) error

DeleteProfile removes configs/<profile>.json and credentials/<profile>.json under dir. If active_config currently points at profile, the pointer file is also cleared so the next LoadConfig call falls back to "default". Missing files are not an error — DeleteProfile is idempotent.

func ListProfiles

func ListProfiles(dir string) ([]string, error)

ListProfiles returns the names of all profiles stored under dir's configs subdirectory, sorted for stable output. A missing configs directory is treated as "no profiles" and returns a nil slice with no error, so callers can enumerate a fresh config root without special-casing first run.

func ProfileCredentialsPath

func ProfileCredentialsPath(dir, profile string) string

ProfileCredentialsPath returns the path to credentials/<profile>.json under dir.

func ProfilePath

func ProfilePath(dir, profile string) string

ProfilePath returns the path to configs/<profile>.json under dir.

func ProfilesDir

func ProfilesDir(dir string) string

ProfilesDir returns the directory containing profile config JSON files.

func RedactOAuthErrorBody

func RedactOAuthErrorBody(body string) string

RedactOAuthErrorBody returns a safe-to-log form of an OAuth token endpoint failure body. If the body parses as a JSON object, only the RFC 6749 §5.2 allowed keys are kept. Non-JSON bodies are replaced with a redaction placeholder. Either way the result is truncated to OAuthErrorBodyMaxLen.

func ResetConfigWarnOnceForTest

func ResetConfigWarnOnceForTest()

ResetConfigWarnOnceForTest clears the warn-once dedupe state so tests can observe a warning a prior test may already have triggered.

func SaveProfile

func SaveProfile(dir, profile string, cfg *Config) error

SaveProfile persists cfg to configs/<profile>.json under dir. The write is atomic (.tmp sibling + rename); the target file is mode 0644 and the configs/ parent is 0755, matching the spec's "non-secret, checkin-safe" positioning for config files (other UIDs on the host — a sidecar, or the CLI running under a different user inside a pod — must be able to read them).

If cfg.AuthenticationInfo.CredentialsPath exactly matches the default resolved path for this profile (i.e. it was populated by LoadConfig defaulting the value, not set explicitly by the caller), it is cleared on write. Otherwise a load → save round-trip would pin the profile config file to the current $HOME via an absolute path, breaking the "checkin-safe, relocatable" design goal.

func SetActiveProfile

func SetActiveProfile(dir, profile string) error

SetActiveProfile writes the active_config pointer under dir so that subsequent LoadConfig calls (without ANTHROPIC_PROFILE set) resolve to profile. The pointer file sits next to configs/ and is written with the "public" config modes.

func WriteCredentials

func WriteCredentials(path string, creds Credentials) error

WriteCredentials persists creds to path atomically. The target file is mode 0600 and the parent directory 0700. Callers typically build path with ProfileCredentialsPath; the signature takes a raw path so tests and non-profile layouts can target arbitrary locations.

Types

type AuthenticationInfo

type AuthenticationInfo struct {
	Type AuthenticationType `json:"-"`

	// CredentialsPath is the path to the credentials JSON file that stores
	// access / refresh tokens on disk. Leave empty to use the default path
	// (credentials/<profile>.json under the config directory). Shared across
	// all authentication types.
	CredentialsPath string `json:"-"`

	// OIDCFederation holds the fields for Type == AuthenticationTypeOIDCFederation.
	// Populated by UnmarshalJSON and inlined by MarshalJSON; never appears as
	// a nested JSON object.
	OIDCFederation *OIDCFederation `json:"-"`

	// UserOAuth holds the fields for Type == AuthenticationTypeUserOAuth.
	// Populated by UnmarshalJSON and inlined by MarshalJSON; never appears as
	// a nested JSON object.
	UserOAuth *UserOAuth `json:"-"`
}

AuthenticationInfo is a tagged union discriminated on AuthenticationInfo.Type. On the wire it is flat: the top-level JSON object holds `type`, the shared `credentials_path`, and the variant-specific fields all at the same level. In Go, the variant-specific fields are grouped into strongly-typed sub-structs (OIDCFederation, UserOAuth) so callers get type safety and a clean non-nil check per variant. Exactly one sub-struct pointer is populated, and it must match AuthenticationInfo.Type.

Because the wire shape is flat, all variant field names share a single namespace at the JSON layer — new variants must pick field names that do not collide with shared fields or with each other.

AuthenticationInfo.UnmarshalJSON silently ignores unknown fields at the JSON layer (per the credentials-file-format spec: "SDKs MUST silently ignore unrecognized top-level keys in both config and credentials files" — the same tolerance rule applies to the nested authentication object). Unknown authentication types still fail loud because the SDK has no way to meaningfully resolve credentials for an unknown variant.

func NewOIDCFederationAuthentication

func NewOIDCFederationAuthentication(oidc OIDCFederation) *AuthenticationInfo

NewOIDCFederationAuthentication builds an AuthenticationInfo for the oidc_federation variant.

func NewUserOAuthAuthentication

func NewUserOAuthAuthentication(clientID string) *AuthenticationInfo

NewUserOAuthAuthentication returns a populated AuthenticationInfo for the user_oauth variant. Pass an empty clientID to describe a profile whose access token is static (no refresh).

func (AuthenticationInfo) MarshalJSON

func (a AuthenticationInfo) MarshalJSON() ([]byte, error)

MarshalJSON emits the flat tagged-union wire shape: shared fields, then the matching variant's fields inlined at the same level. Returns an error when the in-memory state is inconsistent (Type mismatches the populated sub-struct, or neither/both are set).

func (*AuthenticationInfo) UnmarshalJSON

func (a *AuthenticationInfo) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes the flat tagged-union wire shape into the nested Go representation. Unknown fields are silently tolerated per the credentials-file-format spec but are also logged (warn-once) so a user who typo'd a field name at least sees that it was ignored. Unknown authentication types still fail loud.

type AuthenticationType

type AuthenticationType string

AuthenticationType is the discriminator for AuthenticationInfo.

const (
	// AuthenticationTypeOIDCFederation exchanges a third-party OIDC JWT
	// ("identity token") for a short-lived Anthropic access token via the
	// jwt-bearer grant on /v1/oauth/token.
	AuthenticationTypeOIDCFederation AuthenticationType = "oidc_federation"

	// AuthenticationTypeUserOAuth authenticates with an access token minted
	// through a user-interactive OAuth flow (e.g. `anthropic login`), with
	// optional refresh-token rotation when a ClientID is configured.
	AuthenticationTypeUserOAuth AuthenticationType = "user_oauth"
)

type Config

type Config struct {
	// Version is the file-format version. Set to [ConfigFileVersion] by
	// [SaveProfile] on every write; absent on disk implies "1.0".
	Version string `json:"version,omitempty"`

	// AuthenticationInfo describes how this profile authenticates. Required.
	AuthenticationInfo *AuthenticationInfo `json:"authentication"`

	// BaseURL overrides the default API base URL. Optional.
	BaseURL string `json:"base_url,omitempty"`

	// OrganizationID is the Anthropic organization the profile targets.
	OrganizationID string `json:"organization_id,omitempty"`

	// WorkspaceID scopes requests to a specific workspace. For non-federation
	// profiles it is sent as the anthropic-workspace-id request header; for
	// oidc_federation profiles it is sent as workspace_id in the jwt-bearer
	// exchange body instead (the minted token is already workspace-scoped).
	WorkspaceID string `json:"workspace_id,omitempty"`
}

Config holds the raw configuration for authenticating with the Anthropic API. It mirrors the data stored in config files (configs/<profile>.json) and can be constructed manually or loaded from disk with LoadConfig.

Authentication-mode-specific fields live inside AuthenticationInfo, a tagged union discriminated on AuthenticationInfo.Type. Top-level fields apply to every profile regardless of authentication mode.

func LoadConfig

func LoadConfig() (*Config, error)

LoadConfig reads the raw configuration from the Anthropic config file system (configs/<profile>.json) and returns it without resolving credentials. Credential resolution is deferred until the config is passed to [option.WithConfig].

The config directory and profile are resolved using the standard resolution order (ANTHROPIC_CONFIG_DIR, ANTHROPIC_PROFILE, active_config file, defaults).

func LoadProfile

func LoadProfile(dir, profile string) (*Config, error)

LoadProfile loads the config for the named profile from the given config directory, bypassing ANTHROPIC_PROFILE / active_config resolution. Use DefaultDir for the standard location. This is the building block CLIs use to inspect or operate on a profile other than the currently-active one.

type Credentials

type Credentials struct {
	AccessToken  string
	RefreshToken string
	// ExpiresAt is the absolute expiry time of AccessToken. Nil means the
	// token's lifetime is unknown to the SDK (treated as non-expiring by
	// the in-memory cache).
	ExpiresAt *time.Time

	// Scope, OrganizationUUID, OrganizationName, and AccountEmail record
	// what the current AccessToken was actually granted/minted for. They are
	// written on every login and reflect the token's view of the world at
	// mint time. This is distinct from [Config.OrganizationID] on the profile
	// config side, which is the user's intended target org; the two may
	// diverge if the user is reassigned or the token was minted before the
	// profile was edited.
	Scope            string
	OrganizationUUID string
	OrganizationName string
	// AccountEmail is the email of the account that minted the token, taken
	// from the /v1/oauth/token response's account.email_address.
	AccountEmail string
	// WorkspaceID and WorkspaceName record the workspace the token was
	// bound to at mint time (when the authorization carried one). Stored
	// as the tagged `wrkspc_...` form — the same format the CLI flag,
	// profile config, and anthropic-workspace-id header accept. Sourced
	// from the /v1/oauth/token response's workspace.id. Empty for tokens
	// that aren't workspace-scoped.
	WorkspaceID   string
	WorkspaceName string
}

Credentials is the in-memory form of a credentials/<profile>.json file. Not every field is populated for every authentication variant: federation grants, for example, do not return a refresh token.

func ExchangeFederationAssertion

func ExchangeFederationAssertion(ctx context.Context, params FederationExchangeParams) (*Credentials, error)

ExchangeFederationAssertion performs an OAuth 2.0 jwt-bearer exchange against the Anthropic token endpoint and returns the minted credentials.

Federation grants do not return a refresh token — callers re-exchange their assertion on expiry. The returned *Credentials therefore has an empty RefreshToken but a populated ExpiresAt whenever the server returns an expires_in field.

On non-2xx responses the returned error is a *FederationExchangeError carrying the server body and the Request-Id response header.

func (Credentials) MarshalJSON

func (c Credentials) MarshalJSON() ([]byte, error)

func (*Credentials) UnmarshalJSON

func (c *Credentials) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a credentials/<profile>.json file. Unknown fields are silently tolerated per the credentials-file-format spec. A missing "type" is treated as equivalent to "oauth_token" — this is a concession to interop with external tooling (credential daemons, sidecars) that may write plain bearer-token blobs without the discriminator. Every SDK writer emits "type" on write, so missing-type files can only come from outside the SDK; rejecting them would break valid integrations. A type that is set but not "oauth_token" still fails loud.

type FederationExchangeError

type FederationExchangeError struct {
	StatusCode int
	Body       string
	RequestID  string
}

FederationExchangeError is returned by ExchangeFederationAssertion when the token endpoint responds with a non-2xx status. The server body is kept verbatim so the caller can surface the exact upstream message; the Request-Id header is captured separately so support tickets can include a correlation identifier.

func (*FederationExchangeError) Error

func (e *FederationExchangeError) Error() string

type FederationExchangeParams

type FederationExchangeParams struct {
	// Assertion is the signed JWT presented to the token endpoint. Required.
	Assertion string

	// FederationRuleID is the tagged ID ("fdrl_...") of the OidcFederationRule
	// that governs the exchange. Required.
	FederationRuleID string

	// OrganizationID is the tagged ID of the Anthropic organization whose
	// credentials the exchange should mint. Required.
	OrganizationID string

	// ServiceAccountID is an optional "svac_..." target check for
	// federation rules with target_type=SERVICE_ACCOUNT. Leave empty for
	// user-targeted rules.
	ServiceAccountID string

	// WorkspaceID is an optional `wrkspc_*` tagged ID, or the literal
	// "default" to scope the token to the organization's default workspace.
	// When omitted the server picks the rule's sole enabled workspace, else
	// the org default if the rule covers it. Required when the rule enables
	// more than one non-default workspace, or to target a specific workspace
	// other than the one the server would pick. The minted token is
	// workspace-scoped: per-request workspace selection (the
	// anthropic-workspace-id header) is not supported for federation
	// tokens — switching workspaces requires a new token exchange with a
	// different WorkspaceID.
	WorkspaceID string

	// BaseURL overrides the Anthropic API base URL. Defaults to
	// https://api.anthropic.com. A trailing slash is tolerated.
	BaseURL string

	// HTTPClient overrides the default HTTP client used for the exchange.
	// When nil, a client with a 30s timeout is used.
	HTTPClient *http.Client

	// UserAgent overrides the outgoing User-Agent header. When empty, the
	// helper sends "anthropic-sdk-go/<version> ExchangeFederationAssertion"
	// so the token endpoint's access logs identify the caller for
	// incident triage. Callers with their own tooling (e.g. `ant-cli/1.2.3`)
	// should set this so support tickets can point at the real binary.
	UserAgent string
}

FederationExchangeParams captures the inputs needed to exchange a signed third-party assertion (GitHub OIDC, Kubernetes service account token, etc.) for a short-lived Anthropic access token via the jwt-bearer grant.

type IdentityTokenConfig

type IdentityTokenConfig struct {
	Source IdentityTokenSource `json:"source"`
	Path   string              `json:"path,omitempty"`
}

IdentityTokenConfig specifies how to obtain an OIDC identity token for federation exchange.

type IdentityTokenSource

type IdentityTokenSource string

IdentityTokenSource is the source kind for an OIDC identity token.

const (
	// IdentityTokenSourceFile reads the token from a file on every exchange,
	// which supports rotated tokens (e.g. Kubernetes projected service
	// account tokens).
	IdentityTokenSourceFile IdentityTokenSource = "file"
)

type OIDCFederation

type OIDCFederation struct {
	// FederationRuleID is the tagged ID ("fdrl_...") of the OidcFederationRule
	// that governs the exchange. Required.
	FederationRuleID string `json:"federation_rule_id"`

	// ServiceAccountID is an optional expected-target check for federation
	// rules with target_type=SERVICE_ACCOUNT. Must be a "svac_..." tagged ID.
	// Omit for target_type=USER rules, where the principal is derived from
	// the JWT claims.
	ServiceAccountID string `json:"service_account_id,omitempty"`

	// IdentityToken describes how to obtain the OIDC assertion this profile
	// presents at token-exchange time.
	IdentityToken *IdentityTokenConfig `json:"identity_token,omitempty"`

	// Scope is the OAuth scope string (RFC 6749 §3.3 space-delimited form)
	// the profile expects to be granted. It is stored on the profile for
	// display and configuration purposes only — the SDK does NOT send it
	// on the jwt-bearer exchange. The granted scope is determined by the
	// federation rule on the server; IssueOAuthTokenRequest has no scope
	// field, and the REST gateway's alias transformation strips unknown
	// keys, so any attempt to wire this through to the exchange body
	// would be silently dropped. The granted scope appears on the token
	// response's `scope` field, but the SDK does not currently surface
	// it to callers.
	Scope string `json:"scope,omitempty"`
}

OIDCFederation configures a profile that authenticates by exchanging a third-party OIDC identity token for an Anthropic access token. Its fields are inlined into the parent AuthenticationInfo on the wire.

type UserOAuth

type UserOAuth struct {
	// ClientID is the OAuth client ID used for refresh-token exchange. When
	// empty, the access token is treated as static (no refresh) and the
	// profile fails once it expires.
	ClientID string `json:"client_id,omitempty"`

	// Scope is the OAuth scope string (RFC 6749 §3.3 space-delimited form)
	// the profile was granted, captured at login time. The SDK does not
	// consult this on refresh — the oauth-server preserves the original
	// scope set when the refresh request omits scope — but `ant auth status`
	// and similar tools display it.
	Scope string `json:"scope,omitempty"`

	// ConsoleURL is the base URL of the OAuth /authorize page for
	// interactive login. The SDK does not consult it; it's CLI-only state
	// (the `ant auth login` target) that lives on the shared schema so
	// SaveProfile/LoadProfile round-trip it without triggering the
	// unknown-field warning.
	ConsoleURL string `json:"console_url,omitempty"`
}

UserOAuth configures a profile authenticated via a user-interactive OAuth flow. The access and (optional) refresh tokens live on disk under the profile's AuthenticationInfo.CredentialsPath. Its fields are inlined into the parent AuthenticationInfo on the wire.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL