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/identity_token_file.rb,
sig/anthropic/credentials.rbs

Defined Under Namespace

Modules: _AccessTokenProvider, _IdentityTokenProvider 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.

Returns:

  • (String)
"urn:ietf:params:oauth:grant-type:jwt-bearer"
GRANT_TYPE_REFRESH_TOKEN =

OAuth grant type for refresh token exchange.

Returns:

  • (String)
"refresh_token"
TOKEN_ENDPOINT =

Path to the OAuth token endpoint.

Returns:

  • (String)
"/v1/oauth/token"
TOKEN_EXCHANGE_TIMEOUT =

Timeout in seconds for token exchange HTTP requests.

Returns:

  • (Integer)
30
OAUTH_API_BETA_HEADER =

Beta header required for OAuth API requests.

Returns:

  • (String)
"oauth-2025-04-20"
FEDERATION_BETA_HEADER =

Beta header for OIDC federation routing.

Returns:

  • (String)
"oidc-federation-2026-04-01"
ADVISORY_REFRESH_SECONDS =

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

Returns:

  • (Integer)
120
MANDATORY_REFRESH_SECONDS =

Seconds before expiry when refresh becomes mandatory (blocking).

Returns:

  • (Integer)
30
DEFAULT_PROFILE =

Default profile name when none is specified.

Returns:

  • (String)
"default"
DEFAULT_BASE_URL =

Default API base URL.

Returns:

  • (String)
"https://api.anthropic.com"
ENV_API_KEY =

Environment variable for explicit API key authentication.

Returns:

  • (String)
"ANTHROPIC_API_KEY"
ENV_AUTH_TOKEN =

Environment variable for explicit bearer token authentication.

Returns:

  • (String)
"ANTHROPIC_AUTH_TOKEN"
ENV_BASE_URL =

Environment variable for API base URL override.

Returns:

  • (String)
"ANTHROPIC_BASE_URL"
ENV_CONFIG_DIR =

Environment variable to override the config directory location.

Returns:

  • (String)
"ANTHROPIC_CONFIG_DIR"
ENV_PROFILE =

Environment variable to select a specific profile.

Returns:

  • (String)
"ANTHROPIC_PROFILE"
ENV_IDENTITY_TOKEN =

Environment variable for inline identity token (not recommended).

Returns:

  • (String)
"ANTHROPIC_IDENTITY_TOKEN"
ENV_IDENTITY_TOKEN_FILE =

Environment variable for path to identity token file.

Returns:

  • (String)
"ANTHROPIC_IDENTITY_TOKEN_FILE"
ENV_FEDERATION_RULE_ID =

Environment variable for federation rule ID.

Returns:

  • (String)
"ANTHROPIC_FEDERATION_RULE_ID"
ENV_ORGANIZATION_ID =

Environment variable for organization ID.

Returns:

  • (String)
"ANTHROPIC_ORGANIZATION_ID"
ENV_SERVICE_ACCOUNT_ID =

Environment variable for service account ID.

Returns:

  • (String)
"ANTHROPIC_SERVICE_ACCOUNT_ID"
ENV_WORKSPACE_ID =

Environment variable for workspace ID.

Returns:

  • (String)
"ANTHROPIC_WORKSPACE_ID"
ENV_SCOPE =

Environment variable for OAuth scope.

Returns:

  • (String)
"ANTHROPIC_SCOPE"
AUTH_TYPE_OIDC_FEDERATION =

Config file authentication type for OIDC workload identity federation.

Returns:

  • (String)
"oidc_federation"
AUTH_TYPE_USER_OAUTH =

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

Returns:

  • (String)
"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



125
126
127
128
129
130
131
132
# File 'lib/anthropic/credentials/constants.rb', line 125

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



146
147
148
149
150
# File 'lib/anthropic/credentials/constants.rb', line 146

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



177
178
179
180
181
182
183
184
# File 'lib/anthropic/credentials/constants.rb', line 177

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:



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

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



138
139
140
141
# File 'lib/anthropic/credentials/constants.rb', line 138

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

.default_credentials(base_url: DEFAULT_BASE_URL) ⇒ CredentialResult?

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.

Parameters:

  • base_url (String) (defaults to: DEFAULT_BASE_URL)

Returns:



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



155
156
157
# File 'lib/anthropic/credentials/constants.rb', line 155

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



109
110
111
112
113
114
115
# File 'lib/anthropic/credentials/constants.rb', line 109

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



163
164
165
166
167
168
# File 'lib/anthropic/credentials/constants.rb', line 163

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