surshar / claude-code
Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.
Built by Anthropic · github.com/anthropics
Add comprehensive guidance for writing reliable helper scripts that avoid infinite retry loops when VPN or network-dependent credential helpers fail. Includes: - TTL configuration documentation (CLAUDE_CODE_API_KEY_HELPER_TTL_MS) - Timeout best practices for network operations - VPN-aware connectivity checks - Local token caching patterns - Troubleshooting guide for common issues Addresses feedback from New Relic about apiKeyHelper retry loop behavior.
| @@ -264,6 +264,139 @@ | ||
| 264 | 264 | - Time-based authentication |
| 265 | 265 | - Dynamic tenant/workspace selection |
| 266 | 266 | |
| 267 | +### TTL Configuration | |
| 268 | + | |
| 269 | +By default, dynamically generated API keys are cached for 5 minutes. Configure the TTL with: | |
| 270 | + | |
| 271 | +```bash | |
| 272 | +export CLAUDE_CODE_API_KEY_HELPER_TTL_MS=300000 # 5 minutes (default) | |
| 273 | +``` | |
| 274 | + | |
| 275 | +### Writing Robust Helper Scripts | |
| 276 | + | |
| 277 | +Helper scripts can cause issues if they hang or fail repeatedly. Follow these best practices to prevent infinite retry loops and connection hangs: | |
| 278 | + | |
| 279 | +**1. Always set timeouts on network operations:** | |
| 280 | +```bash | |
| 281 | +#!/bin/bash | |
| 282 | +# get-token.sh - Robust token fetcher | |
| 283 | + | |
| 284 | +# Set a timeout for the entire script | |
| 285 | +TIMEOUT_SECONDS=10 | |
| 286 | + | |
| 287 | +# Use timeout for network calls | |
| 288 | +TOKEN=$(timeout ${TIMEOUT_SECONDS}s curl -s --max-time ${TIMEOUT_SECONDS} \ | |
| 289 | + "https://auth.example.com/token" 2>/dev/null) | |
| 290 | + | |
| 291 | +if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then | |
| 292 | + # Exit with error - don't output invalid JSON | |
| 293 | + echo "Failed to fetch token" >&2 | |
| 294 | + exit 1 | |
| 295 | +fi | |
| 296 | + | |
| 297 | +echo "{\"Authorization\": \"Bearer $TOKEN\"}" | |
| 298 | +``` | |
| 299 | + | |
| 300 | +**2. Handle VPN/network dependency failures:** | |
| 301 | +```bash | |
| 302 | +#!/bin/bash | |
| 303 | +# get-headers.sh - VPN-aware token fetcher | |
| 304 | + | |
| 305 | +# Quick connectivity check before attempting auth | |
| 306 | +if ! timeout 2s ping -c 1 vpn-dependent-service.internal >/dev/null 2>&1; then | |
| 307 | + echo "VPN not connected or service unreachable" >&2 | |
| 308 | + exit 1 | |
| 309 | +fi | |
| 310 | + | |
| 311 | +# Proceed with token fetch (with timeout) | |
| 312 | +TOKEN=$(timeout 10s get-token-from-vpn-service) | |
| 313 | + | |
| 314 | +if [ $? -ne 0 ] || [ -z "$TOKEN" ]; then | |
| 315 | + echo "Token fetch failed" >&2 | |
| 316 | + exit 1 | |
| 317 | +fi | |
| 318 | + | |
| 319 | +echo "{\"Authorization\": \"Bearer $TOKEN\"}" | |
| 320 | +``` | |
| 321 | + | |
| 322 | +**3. Cache tokens locally to reduce network calls:** | |
| 323 | +```bash | |
| 324 | +#!/bin/bash | |
| 325 | +# get-headers-cached.sh - Token fetcher with local caching | |
| 326 | + | |
| 327 | +CACHE_FILE="${HOME}/.cache/my-api-token" | |
| 328 | +CACHE_MAX_AGE=240 # seconds (refresh before 5min TTL) | |
| 329 | + | |
| 330 | +# Check cache validity | |
| 331 | +if [ -f "$CACHE_FILE" ]; then | |
| 332 | + CACHE_AGE=$(($(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || stat -f %m "$CACHE_FILE"))) | |
| 333 | + if [ "$CACHE_AGE" -lt "$CACHE_MAX_AGE" ]; then | |
| 334 | + cat "$CACHE_FILE" | |
| 335 | + exit 0 | |
| 336 | + fi | |
| 337 | +fi | |
| 338 | + | |
| 339 | +# Fetch new token with timeout | |
| 340 | +TOKEN=$(timeout 10s fetch-new-token 2>/dev/null) | |
| 341 | + | |
| 342 | +if [ -z "$TOKEN" ]; then | |
| 343 | + # If fetch fails, try to use expired cache as fallback | |
| 344 | + if [ -f "$CACHE_FILE" ]; then | |
| 345 | + echo "Warning: Using expired cached token" >&2 | |
| 346 | + cat "$CACHE_FILE" | |
| 347 | + exit 0 | |
| 348 | + fi | |
| 349 | + echo "Failed to fetch token and no cache available" >&2 | |
| 350 | + exit 1 | |
| 351 | +fi | |
| 352 | + | |
| 353 | +# Update cache | |
| 354 | +mkdir -p "$(dirname "$CACHE_FILE")" | |
| 355 | +echo "{\"Authorization\": \"Bearer $TOKEN\"}" > "$CACHE_FILE" | |
| 356 | +cat "$CACHE_FILE" | |
| 357 | +``` | |
| 358 | + | |
| 359 | +**4. Fail fast with clear error messages:** | |
| 360 | +```bash | |
| 361 | +#!/bin/bash | |
| 362 | +set -e # Exit on any error | |
| 363 | + | |
| 364 | +# Check prerequisites before attempting network calls | |
| 365 | +if [ -z "$API_SECRET" ]; then | |
| 366 | + echo "API_SECRET environment variable not set" >&2 | |
| 367 | + exit 1 | |
| 368 | +fi | |
| 369 | + | |
| 370 | +# Use short timeouts to fail fast | |
| 371 | +TOKEN=$(timeout 5s curl -sf --max-time 5 \ | |
| 372 | + -H "X-Secret: $API_SECRET" \ | |
| 373 | + "https://auth.example.com/token") || { | |
| 374 | + echo "Token request failed or timed out" >&2 | |
| 375 | + exit 1 | |
| 376 | +} | |
| 377 | + | |
| 378 | +echo "{\"Authorization\": \"Bearer $TOKEN\"}" | |
| 379 | +``` | |
| 380 | + | |
| 381 | +### Troubleshooting Helper Scripts | |
| 382 | + | |
| 383 | +**Infinite retry loop / hanging:** | |
| 384 | +- Add timeouts to all network operations | |
| 385 | +- Use `set -e` to exit on errors | |
| 386 | +- Check VPN/network connectivity before making requests | |
| 387 | +- Ensure script outputs valid JSON or exits with error code | |
| 388 | + | |
| 389 | +**Script takes too long:** | |
| 390 | +- Use `timeout` command wrapper | |
| 391 | +- Set `--max-time` on curl requests | |
| 392 | +- Consider caching tokens locally | |
| 393 | +- Reduce TTL if tokens refresh too slowly | |
| 394 | + | |
| 395 | +**VPN-dependent helpers failing:** | |
| 396 | +- Add connectivity check at start of script | |
| 397 | +- Implement graceful degradation with cached tokens | |
| 398 | +- Log clear error messages to stderr | |
| 399 | + | |
| 267 | 400 | ## Security Best Practices |
| 268 | 401 | |
| 269 | 402 | ### DO |