Module: Anthropic::Credentials

Defined in:
lib/anthropic/credentials.rb,
lib/anthropic/credentials/constants.rb,
lib/anthropic/credentials/token_cache.rb,
lib/anthropic/credentials/access_token.rb,
lib/anthropic/credentials/static_token.rb,
lib/anthropic/credentials/config_provider.rb,
lib/anthropic/credentials/credentials_file.rb,
lib/anthropic/credentials/in_memory_config.rb,
lib/anthropic/credentials/workload_identity.rb,
lib/anthropic/credentials/identity_token_file.rb

Defined Under Namespace

Classes: AccessToken, ConfigProvider, CredentialResult, CredentialsFile, IdentityTokenFile, InMemoryConfig, StaticToken, TokenCache, WorkloadIdentity, WorkloadIdentityError

Constant Summary collapse

GRANT_TYPE_JWT_BEARER =

OAuth grant type for RFC 7523 JWT Bearer assertion.

"urn:ietf:params:oauth:grant-type:jwt-bearer"
GRANT_TYPE_REFRESH_TOKEN =

OAuth grant type for refresh token exchange.

"refresh_token"
TOKEN_ENDPOINT =

Path to the OAuth token endpoint.

"/v1/oauth/token"
TOKEN_EXCHANGE_TIMEOUT =

Timeout in seconds for token exchange HTTP requests.

30
OAUTH_API_BETA_HEADER =

Beta header required for OAuth API requests.

"oauth-2025-04-20"
FEDERATION_BETA_HEADER =

Beta header for OIDC federation routing.

"oidc-federation-2026-04-01"
ADVISORY_REFRESH_SECONDS =

Seconds before expiry to attempt advisory (non-blocking) refresh.

120
MANDATORY_REFRESH_SECONDS =

Seconds before expiry when refresh becomes mandatory (blocking).

30
DEFAULT_PROFILE =

Default profile name when none is specified.

"default"
DEFAULT_BASE_URL =

Default API base URL.

"https://api.anthropic.com"
ENV_API_KEY =

Environment variable for explicit API key authentication.

"ANTHROPIC_API_KEY"
ENV_AUTH_TOKEN =

Environment variable for explicit bearer token authentication.

"ANTHROPIC_AUTH_TOKEN"
ENV_BASE_URL =

Environment variable for API base URL override.

"ANTHROPIC_BASE_URL"
ENV_CONFIG_DIR =

Environment variable to override the config directory location.

"ANTHROPIC_CONFIG_DIR"
ENV_PROFILE =

Environment variable to select a specific profile.

"ANTHROPIC_PROFILE"
ENV_IDENTITY_TOKEN =

Environment variable for inline identity token (not recommended).

"ANTHROPIC_IDENTITY_TOKEN"
ENV_IDENTITY_TOKEN_FILE =

Environment variable for path to identity token file.

"ANTHROPIC_IDENTITY_TOKEN_FILE"
ENV_FEDERATION_RULE_ID =

Environment variable for federation rule ID.

"ANTHROPIC_FEDERATION_RULE_ID"
ENV_ORGANIZATION_ID =

Environment variable for organization ID.

"ANTHROPIC_ORGANIZATION_ID"
ENV_SERVICE_ACCOUNT_ID =

Environment variable for service account ID.

"ANTHROPIC_SERVICE_ACCOUNT_ID"
ENV_SCOPE =

Environment variable for OAuth scope.

"ANTHROPIC_SCOPE"
AUTH_TYPE_OIDC_FEDERATION =

Config file authentication type for OIDC workload identity federation.

"oidc_federation"
AUTH_TYPE_USER_OAUTH =

Config file authentication type for user OAuth (interactive login).

"user_oauth"

Class Method Summary collapse

Class Method Details

.active_profileString

Returns the active profile name.

Resolution order:

  1. ANTHROPIC_PROFILE environment variable

  2. active_config pointer file contents

  3. “default”

Returns:

  • (String)

    the active profile name



122
123
124
125
126
127
128
129
# File 'lib/anthropic/credentials/constants.rb', line 122

def active_profile
  return ENV[ENV_PROFILE] if env_present?(ENV_PROFILE)

  pointer = read_active_config_pointer
  return pointer if pointer

  DEFAULT_PROFILE
end

.active_profile_config?Boolean

Checks if the active profile has a config file.

Returns:

  • (Boolean)

    true if the config file exists



143
144
145
146
147
# File 'lib/anthropic/credentials/constants.rb', line 143

def active_profile_config?
  config_file_path(active_profile).file?
rescue StandardError
  false
end

.auto_discoverable_credentials?Boolean

Checks if auto-discoverable credentials are available.

Returns true if the environment or filesystem contains signals that would drive the tier-1 (profile) or tier-2 (env federation) credential paths. Used for shadow-warning detection in the client constructor.

Returns:

  • (Boolean)

    true if auto-discoverable credentials are present



174
175
176
177
178
179
180
181
# File 'lib/anthropic/credentials/constants.rb', line 174

def auto_discoverable_credentials?
  return true if env_present?(ENV_PROFILE)
  return true if env_present?(ENV_CONFIG_DIR)
  return true if explicit_active_config?
  return true if federation_configured?

  false
end

.config_dirPathname

Returns the config directory path.

Resolution order:

  1. ANTHROPIC_CONFIG_DIR environment variable

  2. Platform default:

    • Windows: %APPDATA%Anthropic

    • Unix/macOS: ~/.config/anthropic

Returns:

  • (Pathname)

    the config directory path

Raises:



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/anthropic/credentials/constants.rb', line 84

def config_dir
  return Pathname.new(ENV[ENV_CONFIG_DIR]) if env_present?(ENV_CONFIG_DIR)

  if RUBY_PLATFORM =~ /mswin|mingw|cygwin/ && env_present?("APPDATA")
    return Pathname.new(ENV["APPDATA"]).join("Anthropic")
  end

  begin
    home = Dir.home
    return Pathname.new(home).join(".config", "anthropic") unless home.empty?
  rescue ArgumentError
    # Dir.home raises when HOME is unset. Fall through to the error below.
  end

  raise Anthropic::Errors::ConfigurationError,
        "Cannot determine config directory: neither #{ENV_CONFIG_DIR}, APPDATA, nor HOME is set"
end

.config_file_path(profile) ⇒ Pathname

Returns the path to a profile’s config file.

Parameters:

  • profile (String)

    the profile name

Returns:

  • (Pathname)

    path to <config_dir>/configs/<profile>.json



135
136
137
138
# File 'lib/anthropic/credentials/constants.rb', line 135

def config_file_path(profile)
  base = config_dir
  base.join("configs", "#{profile}.json")
end

.default_credentials(base_url: DEFAULT_BASE_URL) ⇒ Object

Resolve a CredentialResult from the environment per the credential-resolution spec. First match wins.

Implements steps 2-5 of the spec precedence chain (step 1 is handled at the client constructor level):

Step 2a: ANTHROPIC_API_KEY -> return nil so the client uses its

existing +X-Api-Key+ header path. (API keys are not Bearer
tokens, so they can't flow through this chain.)

Step 2b: ANTHROPIC_AUTH_TOKEN -> StaticToken (Bearer). Step 3: ANTHROPIC_PROFILE set -> load that profile. This is

*explicit profile selection* via env var; failures propagate.
Note: the +active_config+ pointer file is **not** treated as
explicit selection -- a leftover pointer from a past `ant
auth login` shouldn't preempt env-var WIF.

Step 4: ANTHROPIC_FEDERATION_RULE_ID + ANTHROPIC_ORGANIZATION_ID

+ +ANTHROPIC_IDENTITY_TOKEN[_FILE]+ -> direct jwt-bearer
exchange via WorkloadIdentity. Critically, step 4 sits
*between* explicit profile (step 3) and fallback profile
(step 5): a machine with WIF env vars wired up must use WIF
even if a leftover +default+ profile (or active_config
pointer) exists on disk, but a user who explicitly sets
+ANTHROPIC_PROFILE=dev+ still gets their profile.

Step 5: Fallback active profile from disk (configs/default.json

or whatever +active_config+ points at). Errors at this step
are swallowed and the chain falls through -- a corrupt
unselected profile shouldn't break an otherwise-explicit
api_key= path.

Returns nil when nothing matches – the client will fall back to its normal “no auth configured” error.



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/anthropic/credentials.rb', line 47

def default_credentials(base_url: DEFAULT_BASE_URL)
  # Step 2a -- env api_key: return nil so the base client handles X-Api-Key.
  # Treat an empty string the same as unset, matching the Python client.
  unless ENV[ENV_API_KEY].to_s.empty?
    return nil
  end

  # Step 2b -- env auth_token: static bearer.
  # Guard against empty string: in Ruby an empty string is truthy, so
  # a bare `if auth_token` would wrap "" in a StaticToken.
  auth_token = ENV[ENV_AUTH_TOKEN]
  if auth_token && !auth_token.empty?
    return CredentialResult.new(provider: StaticToken.new(auth_token))
  end

  # Step 3 -- explicit profile selection via ANTHROPIC_PROFILE env var.
  # Failures propagate -- a user who explicitly names a profile expects
  # a broken config to surface, not to fall through. The active_config
  # pointer file is *not* considered explicit here; it's handled in
  # step 5 so env-var WIF can preempt a stale pointer.
  unless ENV[ENV_PROFILE].to_s.empty?
    creds_file = CredentialsFile.new
    creds_file.bind_base_url(base_url)
    extra_headers = creds_file.extra_headers
    return CredentialResult.new(
      provider: creds_file,
      extra_headers: extra_headers,
      base_url: creds_file.resolved_base_url
    )
  end

  # Step 4 -- env-var workload identity federation. Sits above the
  # fallback on-disk profile so a machine with WIF env vars uses WIF
  # even if a leftover +default+ profile exists on disk.
  federation_result = build_federation_result(base_url: base_url)
  return federation_result if federation_result

  # Step 5 -- fallback active profile from disk. Errors are swallowed and
  # the chain falls through because the user didn't explicitly select
  # this profile; a corrupt auto-discovered config shouldn't break
  # construction.
  #
  # Resolve the profile once and pass it explicitly: active_profile
  # reads the active_config pointer file, and handing the result to
  # CredentialsFile.new avoids a second read inside its constructor.
  profile = Credentials.active_profile
  if Credentials.config_file_path(profile).file?
    creds_file = CredentialsFile.new(profile)
    creds_file.bind_base_url(base_url)
    begin
      extra_headers = creds_file.extra_headers
    rescue Anthropic::Errors::Error
      return nil
    end
    return CredentialResult.new(
      provider: creds_file,
      extra_headers: extra_headers,
      base_url: creds_file.resolved_base_url
    )
  end

  nil
end

.explicit_active_config?Boolean

Checks if there’s an explicit active_config pointer file.

Returns:

  • (Boolean)

    true if the pointer file exists and is non-empty



152
153
154
# File 'lib/anthropic/credentials/constants.rb', line 152

def explicit_active_config?
  !read_active_config_pointer.nil?
end

.read_active_config_pointerString?

Reads the active config pointer file.

Returns:

  • (String, nil)

    the profile name from the pointer file, or nil if the file doesn’t exist or is empty



106
107
108
109
110
111
112
# File 'lib/anthropic/credentials/constants.rb', line 106

def read_active_config_pointer
  path = config_dir.join("active_config")
  content = path.read.strip
  content.empty? ? nil : content
rescue Errno::ENOENT, Errno::EACCES
  nil
end

.resolve_identity_token_path(path = nil) ⇒ Pathname?

Resolves an identity token file path.

Parameters:

  • path (String, nil) (defaults to: nil)

    explicit path, or nil to use environment variable

Returns:

  • (Pathname, nil)

    the resolved path, or nil if not available



160
161
162
163
164
165
# File 'lib/anthropic/credentials/constants.rb', line 160

def resolve_identity_token_path(path = nil)
  return Pathname.new(path) if path
  return Pathname.new(ENV[ENV_IDENTITY_TOKEN_FILE]) if env_present?(ENV_IDENTITY_TOKEN_FILE)

  nil
end