1 line
7.7 KiB
JSON
1 line
7.7 KiB
JSON
{"repo": "anthropics/anthropic-sdk-python", "files": {"examples/workload_identity.py": {"f5c30d0490fb7bcd8e0b65d8d8e63c0e7d1bfe59": {"t": 1785674427.809728, "n": 7328, "h": "88190304487c3327", "c": "#!/usr/bin/env python3\n\"\"\"\nWorkload Identity Federation & Credential Providers — comprehensive examples.\n\nThe Anthropic client resolves auth in this precedence order:\n 1. Constructor args: api_key=, auth_token=, or credentials=\n 2. Env vars: ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, then the credential chain below\n 3. Standard defaults: ~/.config/anthropic/credentials.json if it exists\n\nThe `credentials=` arg accepts any AccessTokenProvider — a zero-arg callable returning\nAccessToken(token, expires_at). The client caches the token and proactively refreshes\nit (120s advisory / 30s mandatory before expiry).\n\"\"\"\n\nimport os\n\nimport anthropic\nfrom anthropic import (\n AccessToken,\n StaticToken,\n CredentialsFile,\n IdentityTokenFile,\n WorkloadIdentityCredentials,\n)\n\n# =============================================================================\n# Section 1: Zero-config (recommended for production workloads)\n# =============================================================================\n# Just construct the client. Auth is resolved from the environment.\n#\n# For Kubernetes / GitHub Actions / etc., set these env vars on the workload:\n# ANTHROPIC_IDENTITY_TOKEN_FILE=/var/run/secrets/kubernetes.io/serviceaccount/token\n# ANTHROPIC_FEDERATION_RULE_ID=fdrl_01...\n# ANTHROPIC_ORGANIZATION_ID=00000000-0000-0000-0000-000000000000\n# ANTHROPIC_SERVICE_ACCOUNT_ID=svac_01... (optional)\n#\n# Or, if a sidecar/daemon writes a profile config + credentials file:\n# ANTHROPIC_PROFILE=my-profile (picks ~/.config/anthropic/configs/my-profile.json\n# and ~/.config/anthropic/credentials/my-profile.json)\n# ANTHROPIC_CONFIG_DIR=/etc/anthropic (relocates the root; optional)\n#\n# Or, the existing env vars still work:\n# ANTHROPIC_API_KEY=sk-ant-...\n# ANTHROPIC_AUTH_TOKEN=sk-ant-oat01-...\n\nclient = anthropic.Anthropic()\n\n\n# =============================================================================\n# Section 2: Explicit credentials= via constructor\n# =============================================================================\n\n# --- 2a. WorkloadIdentityCredentials: exchange an external OIDC JWT --------\n\n# JWT source option i: read from a file (re-read on every refresh — handles k8s rotation)\nclient = anthropic.Anthropic(\n credentials=WorkloadIdentityCredentials(\n identity_token_provider=IdentityTokenFile(\n \"/var/run/secrets/kubernetes.io/serviceaccount/token\",\n ),\n federation_rule_id=\"fdrl_01...\",\n organization_id=\"00000000-0000-0000-0000-000000000000\",\n service_account_id=\"svac_01...\",\n ),\n)\n\n# JWT source option ii: from an env var (CI systems that inject the token directly)\nclient = anthropic.Anthropic(\n credentials=WorkloadIdentityCredentials(\n identity_token_provider=lambda: os.environ[\"ANTHROPIC_IDENTITY_TOKEN\"],\n federation_rule_id=\"fdrl_01...\",\n organization_id=\"00000000-0000-0000-0000-000000000000\",\n ),\n)\n\n\n# JWT source option iii: custom callable (secrets manager, internal token service, etc.)\ndef fetch_jwt_from_vault() -> str:\n # your logic here\n return \"\"\n\n\nclient = anthropic.Anthropic(\n credentials=WorkloadIdentityCredentials(\n identity_token_provider=fetch_jwt_from_vault,\n federation_rule_id=\"fdrl_01...\",\n organization_id=\"00000000-0000-0000-0000-000000000000\",\n ),\n)\n\n# --- 2b. CredentialsFile: read auth config from a named profile on disk ----\n#\n# Profiles live under the config directory (default ~/.config/anthropic/,\n# override with ANTHROPIC_CONFIG_DIR) as a pair of files:\n#\n# configs/<profile>.json — non-secret. Shape:\n#\n# {\n# \"authentication\": {\"type\": \"oidc_federation\"|\"user_oauth\", ...},\n# \"organization_id\": \"00000000-0000-0000-0000-000000000000\",\n# \"workspace_id\": \"wrkspc_01...\",\n# \"base_url\": \"https://api.anthropic.com\"\n# }\n#\n# The \"authentication\" object is a tagged union discriminated on \"type\":\n#\n# {\"type\": \"oidc_federation\",\n# \"federation_rule_id\": \"fdrl_...\",\n# \"service_account_id\": \"svac_...\",\n# \"identity_token\": {\"source\": \"file\", \"path\": \"...\"}}\n# → SDK performs the jwt-bearer exchange itself. If \"identity_token\"\n# is omitted, ANTHROPIC_IDENTITY_TOKEN_FILE is used instead.\n# organization_id is read from the top level of the config.\n#\n# {\"type\": \"user_oauth\", \"client_id\": \"...\"}\n# → interactive PKCE login with refresh_token rotation. On access-token\n# expiry the SDK performs a refresh_token grant against\n# /v1/oauth/token and writes the new tokens back to\n# credentials/<profile>.json (atomic replace).\n#\n# {\"type\": \"user_oauth\"} (no client_id)\n# → credentials file is externally rotated by a sidecar/daemon. The\n# SDK re-reads the file on every refresh and returns whatever\n# access_token is there; no refresh grant is attempted.\n#\n# credentials/<profile>.json — secret (0600). Holds access_token,\n# expires_at, and (for user_oauth with\n# a client_id) refresh_token.\n\n# Point at a specific profile name:\nclient = anthropic.Anthropic(credentials=CredentialsFile(profile=\"production\"))\n# Or resolve the profile from ANTHROPIC_PROFILE / <config_dir>/active_config / \"default\":\nclient = anthropic.Anthropic(credentials=CredentialsFile())\n\n# --- 2c. StaticToken: you already have a bearer token ---------------------\nclient = anthropic.Anthropic(credentials=StaticToken(\"sk-ant-oat01-...\"))\n# (equivalent to anthropic.Anthropic(auth_token=\"sk-ant-oat01-...\"))\n\n\n# --- 2d. Custom AccessTokenProvider ---------------------------------------\n# Any callable matching AccessTokenProvider works. The optional `force_refresh`\n# kwarg is set after a 401 retry; providers without a cache can ignore it.\ndef my_provider(*, force_refresh: bool = False) -> AccessToken: # noqa: ARG001\n # call your internal auth service here\n return AccessToken(token=\"sk-ant-oat01-...\", expires_at=1775000000)\n\n\nclient = anthropic.Anthropic(credentials=my_provider)\n\n# =============================================================================\n# Section 3: Precedence demonstration\n# =============================================================================\n# Constructor args always win over env vars, which win over default file paths.\n# Within constructor args, passing more than one of api_key/auth_token/credentials\n# is supported but credentials takes the Bearer slot (api_key still sends X-Api-Key\n# if both are set — generally don't do this).\n\n# =============================================================================\n# Section 4: Async\n# =============================================================================\n\n\nasync def main() -> None:\n aclient = anthropic.AsyncAnthropic(\n credentials=WorkloadIdentityCredentials(\n identity_token_provider=IdentityTokenFile(), # uses ANTHROPIC_IDENTITY_TOKEN_FILE\n federation_rule_id=\"fdrl_01...\",\n organization_id=\"00000000-0000-0000-0000-000000000000\",\n ),\n )\n msg = await aclient.messages.create(\n model=\"claude-opus-4-5\",\n max_tokens=1024,\n messages=[{\"role\": \"user\", \"content\": \"Hello\"}],\n )\n print(msg)\n\n\n# asyncio.run(main())\n"}}}} |